1%{
2/*
3 * CDDL HEADER START
4 *
5 * The contents of this file are subject to the terms of the
6 * Common Development and Distribution License, Version 1.0 only
7 * (the "License").  You may not use this file except in compliance
8 * with the License.
9 *
10 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
11 * or http://www.opensolaris.org/os/licensing.
12 * See the License for the specific language governing permissions
13 * and limitations under the License.
14 *
15 * When distributing Covered Code, include this CDDL HEADER in each
16 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17 * If applicable, add the following below this CDDL HEADER, with the
18 * fields enclosed by brackets "[]" replaced with your own identifying
19 * information: Portions Copyright [yyyy] [name of copyright owner]
20 *
21 * CDDL HEADER END
22 *
23 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27/*
28 * Overview of poolcfg(1)
29 *
30 * poolcfg(1) implements a small grammar for manipulating pools configurations.
31 * yacc(1) is used to generate the parser and poolcfg.l contains a simple lexer
32 * (generted by lex(1)) to perform lexical processsing of the input.
33 *
34 * Refer to the poolcfg(1) manpage for more details of the grammar.
35 *
36 * The parser is designed so that all operations implement the same interface.
37 * This allows the parser to simply build up the command (using the cmd
38 * variable) by storing arguments and a pointer to the desired function in the
39 * cmd. The command is executed when the commands production is matched.
40 *
41 * Properties and associations are stored in simple linked lists and processed
42 * in the order submitted by the user.
43 */
44
45#include <stdlib.h>
46#include <stdio.h>
47#include <string.h>
48#include <errno.h>
49#include <sys/types.h>
50#include <locale.h>
51#include <libintl.h>
52#include <sys/utsname.h>
53
54#include <pool.h>
55#include "utils.h"
56#include "poolcfg.h"
57
58
59
60#define	USAGE1	\
61"Usage:\n" \
62"%s -h\n" \
63"%s -c command [ -d | [ file ] ]\n" \
64"%s -f command-file [-d | [ file ] ]\n\n"
65
66#define	USAGE2	\
67"command:\n" \
68"  info [entity name]\n" \
69"         display configuration (or specified portion) in readable form\n" \
70"  create entity name [property-list]\n" \
71"         make an entity of the specified type and name\n" \
72"  destroy entity name\n" \
73"         remove the specified entity\n" \
74"  modify entity name [property-list]\n" \
75"         change the listed properties on the named entity\n" \
76"  associate pool name [resource-list]\n" \
77"         connect one or more resources to a pool, or replace one or more\n" \
78"         existing connections\n" \
79"  transfer to resource name [component-list]\n" \
80"         transfer one or more discreet components to a resource\n" \
81"  transfer [quantity] from resource src to tgt\n" \
82"         transfer a resource quantity from src to tgt\n" \
83"  transfer [quantity] to resource tgt from src\n" \
84"         transfer a resource quantity to tgt from src\n" \
85"  discover\n" \
86"         create a system entity, with one pool entity and resources to\n" \
87"         match current system configuration\n" \
88"  rename entity old_name to new_name\n" \
89"         change the name of the entity on the system to its new name\n\n" \
90"property-list:\n" \
91"  ( proptype name = value [ ; proptype name = value ]* )\n" \
92"         where multiple definitions in the sentence for a given\n" \
93"         proptype, name pair are ignored; the last one provided is used.\n" \
94"         For property deletion, use \"~ proptype name\"\n\n" \
95"resource-list:\n" \
96"  ( resource name [; resource name ] )\n" \
97"         where multiple uses of a resource are ignored; the last provided\n" \
98"         is the one used.\n" \
99"         There is no deletion syntax for resource lists.\n" \
100"component-list:\n" \
101"  ( cpu id [; cpu id ] )\n" \
102"         where multiple uses of the same component cause the last provided\n" \
103"         to be the one used.\n" \
104"         There is no deletion syntax for component lists.\n" \
105"entity:\n" \
106"  system | pool | pset | cpu\n" \
107"         where cpu is only valid for transfer, info and modify commands.\n" \
108"resource:\n" \
109"  pset\n\n" \
110"proptype:\n" \
111"  boolean | int | uint | string | float\n\n"
112
113int dofile = PO_FALSE;			/* poolcfg.l uses this for errors */
114int conf_edit_error = POE_OK;		/* cached error for error reporting */
115int conf_edit_errno = 0;		/* cached errno for error reporting */
116int conf_list_error = POE_OK;		/* cached error for error reporting */
117int conf_list_errno = 0;		/* cached errno for error reporting */
118static const char cmdname[] = "poolcfg";
119static const char cmd_options[] = "c:df:h";
120static void usage(int);
121static const char *max_suffix = ".max";
122static const char *min_suffix = ".min";
123
124static const char *conf_file = NULL;	/* Location of target config */
125static cmd_t *cmd = NULL;		/* Command being processed */
126static pool_conf_t *conf = NULL;	/* Config to be processed */
127static int edited = PO_FALSE;		/* Has the configuration been changed */
128
129/* yacc externals */
130extern FILE *yyin;
131extern int yydebug;
132extern void yyerror(char *s);
133
134/* Utility functions */
135static void arg_parse(const char *);
136static void file_parse(const char *);
137static cmd_t *alloc_cmd(void);
138static prop_t *alloc_prop(prop_op_t);
139static assoc_t *alloc_assoc(int, const char *);
140static void free_cmd(cmd_t *);
141static void check_conf_name(cmd_t *);
142static void prop_list_walk(cmd_t *, pool_elem_t *);
143static void assoc_list_walk(cmd_t *, pool_t *);
144static void transfer_list_walk(cmd_t *, pool_resource_t *);
145static void terminate(void);
146static pool_component_t *get_cpu(const char *);
147static void process_min_max(pool_resource_t *);
148
149/* Info Commands */
150static void parser_conf_info(cmd_t *);
151static void parser_pool_info(cmd_t *);
152static void parser_resource_info(cmd_t *, const char *);
153static void parser_pset_info(cmd_t *);
154static void parser_cpu_info(cmd_t *);
155
156/* Create Commands */
157static void parser_conf_create(cmd_t *);
158static void parser_pool_create(cmd_t *);
159static void parser_resource_create(cmd_t *, const char *);
160static void parser_pset_create(cmd_t *);
161
162/* Destroy Commands */
163static void parser_conf_destroy(cmd_t *);
164static void parser_pool_destroy(cmd_t *);
165static void parser_resource_destroy(cmd_t *, const char *);
166static void parser_pset_destroy(cmd_t *);
167
168/* Modify Commands */
169static void parser_conf_modify(cmd_t *);
170static void parser_pool_modify(cmd_t *);
171static void parser_resource_modify(cmd_t *, const char *);
172static void parser_pset_modify(cmd_t *);
173static void parser_cpu_modify(cmd_t *);
174
175/* Associate Commands */
176static void parser_pool_associate(cmd_t *);
177
178/* Assign Commands */
179static void parser_resource_xtransfer(cmd_t *);
180static void parser_resource_transfer(cmd_t *);
181
182/* Discover Commands */
183static void parser_conf_discover(cmd_t *);
184
185/* Rename Commands */
186static void parser_rename(cmd_t *, pool_elem_t *, const char *);
187static void parser_conf_rename(cmd_t *);
188static void parser_pool_rename(cmd_t *);
189static void parser_pset_rename(cmd_t *);
190
191
192%}
193
194%union {
195	double dval;
196	uint64_t uval;
197	int64_t ival;
198	char *sval;
199	uchar_t bval;
200	cmd_t *cmd;
201	prop_t *prop;
202	pv_u val;
203	assoc_t *assoc;
204}
205
206%start commands
207
208%token PCC_INFO PCC_CREATE PCC_DESTROY PCC_MODIFY PCC_ASSOC PCC_DISC PCC_RENAME
209%token PCC_TRANSFER
210%token PCK_FROM PCK_TO PCK_OPENLST PCK_CLOSELST PCK_SEPLST PCK_ASSIGN PCK_UNDEF
211PCK_COMMAND
212%token PCV_FILENAME PCV_SYMBOL PCV_VAL_INT PCV_VAL_UINT PCV_VAL_FLOAT
213PCV_VAL_STRING PCV_VAL_BOOLEAN
214%token PCT_INT PCT_UINT PCT_BOOLEAN PCT_FLOAT PCT_STRING
215%token PCE_SYSTEM PCE_POOL PCE_PSET PCE_CPU
216
217%type <ival> PCV_VAL_INT
218%type <uval> PCV_VAL_UINT
219%type <bval> PCV_VAL_BOOLEAN
220%type <dval> PCV_VAL_FLOAT
221%type <sval> PCV_VAL_STRING
222%type <sval> PCV_SYMBOL
223%type <sval> PCV_FILENAME
224
225%type <ival> PCC_INFO
226%type <ival> PCE_SYSTEM PCE_POOL PCE_PSET PCE_CPU
227%type <ival> entity proptype info_entity modify_entity
228%type <sval> name src tgt
229%type <cmd> command
230%type <cmd> list_command info_command edit_command create_command
231destroy_command modify_command associate_command discover_command
232rename_command transfer_command transfer_qty transfer_components
233%type <prop> prop_remove prop_assign prop_op prop_ops property_list
234%type <assoc> resource_assign resource_assigns resource_list
235%type <assoc> component_assign component_assigns component_list
236%type <val> value
237%type <ival> resource component
238
239%%
240
241commands: command
242	{
243		if ($1->cmd != NULL)
244			$1->cmd($1);
245		free_cmd($1);
246	}
247	| commands command
248	{
249		if ($2->cmd != NULL)
250			$2->cmd($2);
251		free_cmd($2);
252	}
253	| command error { YYERROR;};
254
255command: list_command
256	| edit_command
257	{
258		if (conf_edit_error != POE_OK) {
259			if ($1->cmd != parser_conf_create &&
260			    $1->cmd != parser_conf_discover) {
261				die(gettext(ERR_CONF_LOAD), conf_file,
262				    get_errstr_err(conf_edit_error,
263				        conf_edit_errno));
264			}
265		}
266		edited = PO_TRUE;
267	};
268
269list_command: info_command
270	{
271		if (conf_list_error != POE_OK) {
272			if ($1->cmd != parser_conf_create &&
273			    $1->cmd != parser_conf_discover) {
274				die(gettext(ERR_CONF_LOAD), conf_file,
275				    get_errstr_err(conf_list_error,
276				        conf_list_errno));
277			}
278		}
279	}
280	| discover_command {conf_list_error = conf_edit_error = POE_OK;};
281
282edit_command: create_command
283	| destroy_command
284	| modify_command
285	| associate_command
286	| transfer_command
287	| rename_command;
288
289info_command: PCC_INFO
290	{
291		if (($$ = alloc_cmd()) == NULL)
292			YYERROR;
293		cmd = $$;
294		$$->cmd = &parser_conf_info;
295	}
296	| PCC_INFO info_entity name
297	{
298		if (($$ = alloc_cmd()) == NULL)
299			YYERROR;
300		cmd = $$;
301		switch ($2) {
302		case PCE_SYSTEM:
303			$$->cmd = &parser_conf_info;
304			break;
305		case PCE_POOL:
306			$$->cmd = &parser_pool_info;
307			break;
308		case PCE_PSET:
309			$$->cmd = &parser_pset_info;
310			break;
311		case PCE_CPU:
312			$$->cmd = &parser_cpu_info;
313			break;
314		default:
315			warn(gettext(ERR_UNKNOWN_ENTITY), $2);
316			YYERROR;
317		}
318		$$->cmd_tgt1 = $3;
319	};
320
321create_command: PCC_CREATE entity name
322	{
323		if (($$ = alloc_cmd()) == NULL)
324			YYERROR;
325		cmd = $$;
326		switch ($2) {
327		case PCE_SYSTEM:
328			$$->cmd = &parser_conf_create;
329			/*
330			 * When creating a new system element, ensure
331			 * pre-existing errors are ignored.
332			 */
333			conf_list_error = conf_edit_error = POE_OK;
334			break;
335		case PCE_POOL:
336			$$->cmd = &parser_pool_create;
337			break;
338		case PCE_PSET:
339			$$->cmd = &parser_pset_create;
340			break;
341		default:
342			warn(gettext(ERR_UNKNOWN_ENTITY), $2);
343			YYERROR;
344		}
345		$$->cmd_tgt1 = $3;
346	}
347	| create_command property_list;
348
349destroy_command: PCC_DESTROY entity name
350	{
351		if (($$ = alloc_cmd()) == NULL)
352			YYERROR;
353		cmd = $$;
354		switch ($2) {
355		case PCE_SYSTEM:
356			$$->cmd = &parser_conf_destroy;
357			break;
358		case PCE_POOL:
359			$$->cmd = &parser_pool_destroy;
360			break;
361		case PCE_PSET:
362			$$->cmd = &parser_pset_destroy;
363			break;
364		default:
365			warn(gettext(ERR_UNKNOWN_ENTITY), $2);
366			YYERROR;
367		}
368		$$->cmd_tgt1 = $3;
369	};
370
371modify_command: PCC_MODIFY modify_entity name
372	{
373		if (($$ = alloc_cmd()) == NULL)
374			YYERROR;
375		cmd = $$;
376		switch ($2) {
377		case PCE_SYSTEM:
378			$$->cmd = &parser_conf_modify;
379			break;
380		case PCE_POOL:
381			$$->cmd = &parser_pool_modify;
382			break;
383		case PCE_PSET:
384			$$->cmd = &parser_pset_modify;
385			break;
386		case PCE_CPU:
387			$$->cmd = &parser_cpu_modify;
388			break;
389		default:
390			warn(gettext(ERR_UNKNOWN_ENTITY), $2);
391			YYERROR;
392		}
393		$$->cmd_tgt1 = $3;
394	}
395	| modify_command property_list;
396
397associate_command: PCC_ASSOC PCE_POOL name
398	{
399		if (($$ = alloc_cmd()) == NULL)
400			YYERROR;
401		cmd = $$;
402		$$->cmd = &parser_pool_associate;
403		cmd->cmd_tgt1 = $3;
404	}
405	| associate_command resource_list;
406
407transfer_command: transfer_qty
408	| transfer_components;
409
410transfer_components: PCC_TRANSFER PCK_TO PCE_PSET name
411	{
412		if (($$ = alloc_cmd()) == NULL)
413			YYERROR;
414		cmd = $$;
415		$$->cmd = &parser_resource_xtransfer;
416		cmd->cmd_tgt1 = $4;
417	}
418	| transfer_components component_list;
419
420transfer_qty: PCC_TRANSFER PCV_VAL_UINT PCK_FROM PCE_PSET src PCK_TO tgt
421	{
422		if (($$ = alloc_cmd()) == NULL)
423			YYERROR;
424		cmd = $$;
425		$$->cmd = &parser_resource_transfer;
426		cmd->cmd_tgt1 = $5;
427		cmd->cmd_tgt2 = $7;
428		cmd->cmd_qty = $2;
429	}
430	| PCC_TRANSFER  PCV_VAL_UINT PCK_TO PCE_PSET tgt PCK_FROM src
431	{
432		if (($$ = alloc_cmd()) == NULL)
433			YYERROR;
434		cmd = $$;
435		$$->cmd = &parser_resource_transfer;
436		cmd->cmd_tgt1 = $7;
437		cmd->cmd_tgt2 = $5;
438		cmd->cmd_qty = $2;
439	};
440
441discover_command: PCC_DISC
442	{
443		if (($$ = alloc_cmd()) == NULL)
444			YYERROR;
445		cmd = $$;
446		$$->cmd = &parser_conf_discover;
447	};
448
449rename_command: PCC_RENAME entity name PCK_TO name
450	{
451		if (($$ = alloc_cmd()) == NULL)
452			YYERROR;
453		cmd = $$;
454		switch ($2) {
455		case PCE_SYSTEM:
456			$$->cmd = &parser_conf_rename;
457			break;
458		case PCE_POOL:
459			$$->cmd = &parser_pool_rename;
460			break;
461		case PCE_PSET:
462			$$->cmd = &parser_pset_rename;
463			break;
464		default:
465			warn(gettext(ERR_UNKNOWN_ENTITY), $2);
466			YYERROR;
467		}
468		$$->cmd_tgt1 = $3;
469		$$->cmd_tgt2 = $5;
470	};
471
472modify_entity: entity
473	| PCE_CPU  {$$ = PCE_CPU;};
474
475info_entity: entity
476	| PCE_CPU  {$$ = PCE_CPU;};
477
478entity: PCE_SYSTEM {$$ = PCE_SYSTEM;}
479	| PCE_POOL {$$ = PCE_POOL;}
480	| PCE_PSET {$$ = PCE_PSET;};
481
482name: PCV_SYMBOL;
483
484src: PCV_SYMBOL;
485
486tgt: PCV_SYMBOL;
487
488value: PCV_VAL_INT { $$.i = $1;}
489	| PCV_VAL_UINT { $$.u = $1;}
490	| PCV_VAL_FLOAT { $$.d = $1;}
491	| PCV_VAL_BOOLEAN { $$.b = $1;}
492	| PCV_VAL_STRING { $$.s = $1;};
493
494prop_remove: PCK_UNDEF proptype name
495	{
496		if (($$ = alloc_prop(po_remove)) == NULL)
497			YYERROR;
498		$$->prop_name = $3;
499	};
500
501prop_op: prop_assign
502	| prop_remove;
503
504prop_ops: prop_op
505	{
506		prop_t *prop = NULL;
507		prop_t *prev = NULL;
508
509		for (prop = cmd->cmd_prop_list; prop != NULL;
510		    prop = prop->prop_next)
511			prev = prop; /* Find end of list */
512		if (prev != NULL)
513			prev->prop_next = $1;
514		else
515			cmd->cmd_prop_list = $1;
516		$$ = cmd->cmd_prop_list;
517	}
518	| prop_ops PCK_SEPLST prop_op
519	{
520		prop_t *prop = NULL;
521		prop_t *prev = NULL;
522
523		for (prop = cmd->cmd_prop_list; prop != NULL;
524		    prop = prop->prop_next)
525			prev = prop; /* Find end of list */
526		if (prev != NULL)
527			prev->prop_next = $3;
528		else
529			cmd->cmd_prop_list = $3;
530		$$ = cmd->cmd_prop_list;
531
532	};
533
534prop_assign: proptype name PCK_ASSIGN value
535	{
536		if (($$ = alloc_prop(po_create)) == NULL)
537			YYERROR;
538		$$->prop_name = $2;
539		switch ($1) {
540		case PCT_INT:
541			pool_value_set_int64($$->prop_value, $4.i);
542			break;
543		case PCT_UINT:
544			pool_value_set_uint64($$->prop_value, $4.u);
545			break;
546		case PCT_BOOLEAN:
547			pool_value_set_bool($$->prop_value, $4.b);
548			break;
549		case PCT_FLOAT:
550			pool_value_set_double($$->prop_value, $4.d);
551			break;
552		case PCT_STRING:
553			pool_value_set_string($$->prop_value, $4.s);
554			break;
555		}
556	};
557
558property_list: PCK_OPENLST prop_ops PCK_CLOSELST
559	{
560		$$ = $2;
561	};
562
563resource_assigns: resource_assign
564	{
565		assoc_t *assoc = NULL;
566		assoc_t *prev = NULL;
567
568		for (assoc = cmd->cmd_assoc_list; assoc != NULL;
569		    assoc = assoc->assoc_next)
570			prev = assoc; /* Find end of list */
571		if (prev != NULL)
572			prev->assoc_next = $1;
573		else
574			cmd->cmd_assoc_list = $1;
575		$$ = cmd->cmd_assoc_list;
576	}
577
578	| resource_assigns PCK_SEPLST resource_assign
579	{
580		assoc_t *assoc = NULL;
581		assoc_t *prev = NULL;
582
583		for (assoc = cmd->cmd_assoc_list; assoc != NULL;
584		    assoc = assoc->assoc_next)
585			prev = assoc; /* Find end of list */
586		if (prev != NULL)
587			prev->assoc_next = $3;
588		$$ = $3;
589	};
590
591resource_assign: resource name
592	{
593		if (($$ = alloc_assoc($1, $2)) == NULL)
594			YYERROR;
595	};
596
597resource: PCE_PSET {$$ = PCE_PSET;};
598
599resource_list: PCK_OPENLST resource_assigns PCK_CLOSELST
600	{
601		$$ = $2;
602	};
603
604component_assigns: component_assign
605	{
606		assoc_t *assoc = NULL;
607		assoc_t *prev = NULL;
608
609		for (assoc = cmd->cmd_assoc_list; assoc != NULL;
610		    assoc = assoc->assoc_next)
611			prev = assoc; /* Find end of list */
612		if (prev != NULL)
613			prev->assoc_next = $1;
614		else
615			cmd->cmd_assoc_list = $1;
616		$$ = cmd->cmd_assoc_list;
617	}
618
619	| component_assigns PCK_SEPLST component_assign
620	{
621		assoc_t *assoc = NULL;
622		assoc_t *prev = NULL;
623
624		for (assoc = cmd->cmd_assoc_list; assoc != NULL;
625		    assoc = assoc->assoc_next)
626			prev = assoc; /* Find end of list */
627		if (prev != NULL)
628			prev->assoc_next = $3;
629		$$ = $3;
630	};
631
632component_list: PCK_OPENLST component_assigns PCK_CLOSELST
633	{
634		$$ = $2;
635	};
636
637component_assign: component name
638	{
639		if (($$ = alloc_assoc($1, $2)) == NULL)
640			YYERROR;
641	};
642
643component: PCE_CPU {$$ = PCE_CPU;};
644
645proptype: PCT_INT {$$ = PCT_INT;}
646	| PCT_UINT {$$ = PCT_UINT;}
647	| PCT_BOOLEAN {$$ = PCT_BOOLEAN;}
648	| PCT_FLOAT {$$ = PCT_FLOAT;}
649	| PCT_STRING {$$ = PCT_STRING;};
650
651%%
652
653#ifndef	TEXT_DOMAIN
654#define	TEXT_DOMAIN "SYS_TEST"
655#endif
656
657int
658main(int argc, char *argv[])
659{
660	int opt;
661	int docmd = PO_FALSE;
662
663	(void) getpname(argv[0]);
664	(void) setlocale(LC_ALL, "");
665	(void) textdomain(TEXT_DOMAIN);
666	if (atexit(terminate) != 0) {
667		die(gettext(ERR_SET_TERM), get_errstr());
668	}
669
670	conf_file = pool_static_location();
671
672	yydebug = 0;
673	while ((opt = getopt(argc, argv, cmd_options)) != (int)EOF) {
674
675		switch (opt) {
676		case 'c': /* Process command line */
677			if (dofile == PO_TRUE)
678				usage(1);
679			arg_parse(optarg);
680			docmd = PO_TRUE;
681			break;
682		case 'd': /* Manipulate dynamic configuration */
683			conf_file = pool_dynamic_location();
684			break;
685		case 'f': /* Process command file */
686			if (docmd == PO_TRUE)
687				usage(1);
688			file_parse(optarg);
689			dofile = PO_TRUE;
690			break;
691		case 'h':
692			usage(2);
693			break;
694		case '?':
695		default:
696			usage(1);
697			break;
698		}
699	}
700	if (docmd == PO_FALSE && dofile == PO_FALSE)
701		usage(1);
702
703	if (optind == argc - 1) {
704		if (strcmp(conf_file, pool_dynamic_location()) == 0)
705			usage(1);
706		conf_file = argv[optind];
707	} else if (optind <  argc - 1)
708		usage(1);
709
710	if ((conf = pool_conf_alloc()) == NULL) {
711		die(gettext(ERR_ALLOC_ELEMENT), gettext(CONFIGURATION),
712		    get_errstr());
713	}
714	/*
715	 * Opening a conf is complex, since we may be opening one of the
716	 * following:
717	 *	- An existing configuration that we can modify
718	 *	- An existing configuration that we can't modify
719	 *	- A new configuration that we can modify
720	 *	- A new configuration that we can't modify
721	 * The parser_conf_discover() function closes the file and reopens
722	 * in PO_CREAT mode, so we only need be concerned here with the
723	 * first two cases.
724	 * Always try to open RDWR, if fail try RDONLY. Don't check
725	 * if that fails, since we may be trying to discover a configuration
726	 * in which case it's valid for both open attempts to fail. Later, when
727	 * processing commands, if we don't have a valid configuration and
728	 * we are trying to process a command which isn't a create or a discover
729	 * we will fail the command as there is no valid configuration to
730	 * work with.
731	 */
732	if (pool_conf_open(conf, conf_file, PO_RDWR) != 0) {
733		conf_edit_error = pool_error();
734		conf_edit_errno = errno;
735		if (pool_conf_open(conf, conf_file, PO_RDONLY) != 0) {
736			conf_list_error = pool_error();
737			conf_list_errno = errno;
738		}
739	}
740
741	if (yyparse() == 0) {
742		if (pool_conf_status(conf) >= POF_VALID) {
743			if (pool_conf_validate(conf, POV_STRICT) == PO_FAIL) {
744				die(gettext(ERR_VALIDATION_FAILED),
745				    get_errstr());
746			}
747			/*
748			 * If the user attempted to change the configuration,
749			 * then we should try to save the changes.
750			 */
751			if (edited == PO_TRUE) {
752				if (pool_conf_commit(conf, 0) == PO_FAIL) {
753					die(gettext(ERR_CONFIG_SAVE_FAILED),
754					    get_errstr());
755				}
756			}
757			pool_conf_close(conf);
758		}
759	} else {
760		die(gettext(ERR_CMDPARSE_FAILED));
761	}
762
763	/*
764	 * Cleanup is performed in terminate(), using atexit
765	 */
766	return (0);
767}
768
769/*
770 * Info Commands
771 * Invoke the appropriate libpool info function and display the returned
772 * information.
773 */
774static void
775parser_conf_info(cmd_t *cmd)
776{
777	char *info_buf;
778	const char *tgt = cmd->cmd_tgt1;
779	pool_value_t *pv = NULL;
780	pool_elem_t *pe;
781
782	if ((pe = pool_conf_to_elem(conf)) == NULL)
783		die(gettext(ERR_GET_ELEMENT_DETAILS),
784		    gettext(CONFIGURATION), "unknown", get_errstr());
785
786	if (tgt != NULL)
787		check_conf_name(cmd);
788	else {
789		if ((pv = pool_value_alloc()) == NULL)
790			die(gettext(ERR_GET_ELEMENT_DETAILS),
791			    gettext(CONFIGURATION), "unknown", get_errstr());
792		if (pool_get_property(conf, pe, "system.name", pv) ==
793		    POC_INVAL ||
794		    pool_value_get_string(pv, &tgt) != PO_SUCCESS)
795			die(gettext(ERR_GET_ELEMENT_DETAILS),
796			    gettext(CONFIGURATION), "unknown", get_errstr());
797	}
798	if ((info_buf = pool_conf_info(conf, PO_TRUE)) == NULL) {
799		die(gettext(ERR_GET_ELEMENT_DETAILS), gettext(CONFIGURATION),
800		    tgt, get_errstr());
801	}
802	if (pv != NULL) {
803		pool_value_free(pv);
804	}
805	(void) printf("%s\n", info_buf);
806	free(info_buf);
807}
808
809static void
810parser_pool_info(cmd_t *cmd)
811{
812	pool_t *pool;
813	char *info_buf;
814
815	if ((pool = pool_get_pool(conf, cmd->cmd_tgt1)) == NULL)
816		die(gettext(ERR_LOCATE_ELEMENT), gettext(POOL), cmd->cmd_tgt1,
817		    get_errstr());
818
819	if ((info_buf = pool_info(conf, pool, PO_TRUE)) == NULL)
820		die(gettext(ERR_GET_ELEMENT_DETAILS), gettext(POOL),
821		    cmd->cmd_tgt1, get_errstr());
822	(void) printf("%s\n", info_buf);
823	free(info_buf);
824}
825
826static void
827parser_resource_info(cmd_t *cmd, const char *type)
828{
829	pool_resource_t *resource;
830	char *info_buf;
831
832	if ((resource = pool_get_resource(conf, type, cmd->cmd_tgt1)) == NULL)
833		die(gettext(ERR_LOCATE_ELEMENT), gettext(RESOURCE),
834		    cmd->cmd_tgt1, get_errstr());
835
836	if ((info_buf = pool_resource_info(conf, resource, PO_TRUE)) == NULL)
837		die(gettext(ERR_GET_ELEMENT_DETAILS), gettext(RESOURCE),
838		    cmd->cmd_tgt1, get_errstr());
839	(void) printf("%s\n", info_buf);
840	free(info_buf);
841}
842
843static void
844parser_pset_info(cmd_t *cmd)
845{
846	parser_resource_info(cmd, PSET);
847}
848
849static void
850parser_cpu_info(cmd_t *cmd)
851{
852	pool_component_t *comp;
853	char *info_buf;
854
855	if ((comp = get_cpu(cmd->cmd_tgt1)) == NULL)
856		die(gettext(ERR_LOCATE_ELEMENT), gettext(CPU),
857		    cmd->cmd_tgt1, get_errstr());
858	if ((info_buf = pool_component_info(conf, comp, PO_TRUE)) == NULL) {
859		die(gettext(ERR_GET_ELEMENT_DETAILS), gettext(CPU),
860		    cmd->cmd_tgt1, get_errstr());
861	}
862	(void) printf("%s\n", info_buf);
863	free(info_buf);
864}
865
866/*
867 * Create Commands
868 * Invoke the appropriate libpool create function and perform any requested
869 * property operations.
870 */
871static void
872parser_conf_create(cmd_t *cmd)
873{
874	const char *tmp_name;
875	pool_elem_t *pe;
876
877	if (conf != NULL && pool_conf_status(conf) >= POF_VALID)
878		pool_conf_close(conf);
879	if (pool_conf_open(conf, conf_file, PO_CREAT) != 0) {
880		die(gettext(ERR_CREATE_ELEMENT), gettext(CONFIGURATION),
881		    cmd->cmd_tgt1, get_errstr());
882	}
883	tmp_name = cmd->cmd_tgt1;
884	cmd->cmd_tgt1 = cmd->cmd_tgt2;
885	cmd->cmd_tgt2 = tmp_name;
886	parser_conf_rename(cmd);
887	if ((pe = pool_conf_to_elem(conf)) == NULL)
888		die(gettext(ERR_GET_ELEMENT_DETAILS),
889		    gettext(CONFIGURATION), "unknown", get_errstr());
890	prop_list_walk(cmd, pe);
891}
892
893static void
894parser_pool_create(cmd_t *cmd)
895{
896	pool_t *pool;
897
898	if ((pool = pool_create(conf, cmd->cmd_tgt1)) == NULL)
899		die(gettext(ERR_CREATE_ELEMENT), gettext(POOL), cmd->cmd_tgt1,
900		    get_errstr());
901	prop_list_walk(cmd, pool_to_elem(conf, pool));
902}
903
904static void
905parser_resource_create(cmd_t *cmd, const char *type)
906{
907	pool_resource_t *resource;
908
909	if ((resource = pool_resource_create(conf, type, cmd->cmd_tgt1))
910	    == NULL)
911		die(gettext(ERR_CREATE_ELEMENT), type, cmd->cmd_tgt1,
912		    get_errstr());
913
914	process_min_max(resource);
915
916	prop_list_walk(cmd, pool_resource_to_elem(conf, resource));
917}
918
919static void
920parser_pset_create(cmd_t *cmd)
921{
922	parser_resource_create(cmd, PSET);
923}
924
925/*
926 * Rename Commands
927 * Rename the target by calling pool_put_property for the name property.
928 */
929static void
930parser_rename(cmd_t *cmd, pool_elem_t *pe, const char *name)
931{
932	pool_value_t *pv;
933
934	if ((pv = pool_value_alloc()) == NULL) {
935		die(gettext(ERR_ALLOC_ELEMENT), gettext(RESOURCE),
936		    get_errstr());
937	}
938	pool_value_set_string(pv, cmd->cmd_tgt2);
939	if (pool_put_property(conf, pe, name, pv) != 0)
940		die(gettext(ERR_PUT_PROPERTY), name, get_errstr());
941	pool_value_free(pv);
942}
943
944static void
945parser_conf_rename(cmd_t *cmd)
946{
947	pool_elem_t *pe;
948
949	if ((pe = pool_conf_to_elem(conf)) == NULL)
950		die(gettext(ERR_GET_ELEMENT_DETAILS),
951		    gettext(CONFIGURATION), "unknown", get_errstr());
952
953	if (cmd->cmd_tgt1 != NULL)
954		check_conf_name(cmd);
955
956	parser_rename(cmd, pe, SYSTEM_NAME);
957}
958
959static void
960parser_pool_rename(cmd_t *cmd)
961{
962	pool_t *pool;
963
964	if ((pool = pool_get_pool(conf, cmd->cmd_tgt1)) == NULL)
965		die(gettext(ERR_LOCATE_ELEMENT), gettext(POOL), cmd->cmd_tgt1,
966		    get_errstr());
967
968	parser_rename(cmd, pool_to_elem(conf, pool), POOL_NAME);
969}
970
971static void
972parser_pset_rename(cmd_t *cmd)
973{
974	pool_resource_t *resource;
975
976	if ((resource = pool_get_resource(conf, PSET, cmd->cmd_tgt1)) == NULL)
977		die(gettext(ERR_LOCATE_ELEMENT), gettext(PSET), cmd->cmd_tgt1,
978		    get_errstr());
979
980	parser_rename(cmd, pool_resource_to_elem(conf, resource), PSET_NAME);
981}
982
983/*
984 * Destroy Commands
985 * Invoke the appropriate libpool destroy function to remove the target of the
986 * command from the configuration.
987 */
988static void
989parser_conf_destroy(cmd_t *cmd)
990{
991	if (cmd->cmd_tgt1 != NULL)
992		check_conf_name(cmd);
993
994	if (pool_conf_remove(conf) != 0)
995		die(gettext(ERR_DESTROY_ELEMENT), gettext(CONFIGURATION),
996		    cmd->cmd_tgt1, get_errstr());
997}
998
999static void
1000parser_pool_destroy(cmd_t *cmd)
1001{
1002	pool_t *pool;
1003
1004	if ((pool = pool_get_pool(conf, cmd->cmd_tgt1)) == NULL)
1005		die(gettext(ERR_LOCATE_ELEMENT), gettext(POOL), cmd->cmd_tgt1,
1006		    get_errstr());
1007
1008	if (pool_destroy(conf, pool) != 0)
1009		die(gettext(ERR_DESTROY_ELEMENT), gettext(POOL), cmd->cmd_tgt1,
1010		    get_errstr());
1011}
1012
1013static void
1014parser_resource_destroy(cmd_t *cmd, const char *type)
1015{
1016	pool_resource_t *resource;
1017
1018	if ((resource = pool_get_resource(conf, type, cmd->cmd_tgt1)) == NULL)
1019		die(gettext(ERR_LOCATE_ELEMENT), type, cmd->cmd_tgt1,
1020		    get_errstr());
1021
1022	if (pool_resource_destroy(conf, resource) != 0)
1023		die(gettext(ERR_DESTROY_ELEMENT), type, cmd->cmd_tgt1,
1024		    get_errstr());
1025}
1026
1027static void
1028parser_pset_destroy(cmd_t *cmd)
1029{
1030	parser_resource_destroy(cmd, PSET);
1031}
1032
1033/*
1034 * Modify Commands
1035 * Perform any requested property operations.
1036 */
1037static void
1038parser_conf_modify(cmd_t *cmd)
1039{
1040	pool_elem_t *pe;
1041
1042	if ((pe = pool_conf_to_elem(conf)) == NULL)
1043		die(gettext(ERR_GET_ELEMENT_DETAILS),
1044		    gettext(CONFIGURATION), "unknown", get_errstr());
1045
1046	if (cmd->cmd_tgt1 != NULL)
1047		check_conf_name(cmd);
1048
1049	prop_list_walk(cmd, pe);
1050}
1051
1052static void
1053parser_pool_modify(cmd_t *cmd)
1054{
1055	pool_t *pool;
1056
1057	if ((pool = pool_get_pool(conf, cmd->cmd_tgt1)) == NULL)
1058		die(gettext(ERR_LOCATE_ELEMENT), gettext(POOL), cmd->cmd_tgt1,
1059		    get_errstr());
1060	prop_list_walk(cmd, pool_to_elem(conf, pool));
1061}
1062
1063static void
1064parser_resource_modify(cmd_t *cmd, const char *type)
1065{
1066	pool_resource_t *resource;
1067
1068	if ((resource = pool_get_resource(conf, type, cmd->cmd_tgt1)) == NULL)
1069		die(gettext(ERR_LOCATE_ELEMENT), gettext(RESOURCE),
1070		    cmd->cmd_tgt1, get_errstr());
1071
1072	process_min_max(resource);
1073
1074	prop_list_walk(cmd, pool_resource_to_elem(conf, resource));
1075}
1076
1077static void
1078parser_pset_modify(cmd_t *cmd)
1079{
1080	parser_resource_modify(cmd, PSET);
1081}
1082
1083static void
1084parser_cpu_modify(cmd_t *cmd)
1085{
1086	pool_component_t *comp;
1087
1088	if ((comp = get_cpu(cmd->cmd_tgt1)) == NULL)
1089		die(gettext(ERR_LOCATE_ELEMENT), gettext(CPU),
1090		    cmd->cmd_tgt1, get_errstr());
1091	prop_list_walk(cmd, pool_component_to_elem(conf, comp));
1092}
1093
1094/*
1095 * Discover Commands
1096 * Invoke the libpool pool_conf_open function so that discovery will be
1097 * performed.
1098 */
1099
1100/*ARGSUSED*/
1101static void
1102parser_conf_discover(cmd_t *cmd)
1103{
1104	struct utsname utsname;
1105
1106	if (strcmp(conf_file, pool_dynamic_location()) == 0)
1107		return;
1108
1109	if (uname(&utsname) < 0)
1110		die(gettext(ERR_CREATE_ELEMENT), gettext(CONFIGURATION),
1111		    "unknown", get_errstr());
1112
1113	if (conf != NULL && pool_conf_status(conf) >= POF_VALID)
1114		pool_conf_close(conf);
1115	if (pool_conf_open(conf, pool_dynamic_location(), PO_RDONLY) != 0) {
1116		die(gettext(ERR_CREATE_ELEMENT), gettext(CONFIGURATION),
1117		    utsname.nodename, get_errstr());
1118	}
1119	if (pool_conf_export(conf, conf_file, POX_NATIVE) != 0) {
1120		die(gettext(ERR_CREATE_ELEMENT), gettext(CONFIGURATION),
1121		    utsname.nodename, get_errstr());
1122	}
1123	(void) pool_conf_close(conf);
1124	if (pool_conf_open(conf, conf_file, PO_RDWR) != 0) {
1125		die(gettext(ERR_CREATE_ELEMENT), gettext(CONFIGURATION),
1126		    utsname.nodename, get_errstr());
1127	}
1128}
1129
1130/*
1131 * Associate Commands
1132 * Walk the list of specified associations so that the target pool will be
1133 * associated with the required resources.
1134 */
1135
1136static void
1137parser_pool_associate(cmd_t *cmd)
1138{
1139	pool_t *pool;
1140
1141	if ((pool = pool_get_pool(conf, cmd->cmd_tgt1)) == NULL)
1142		die(gettext(ERR_LOCATE_ELEMENT), gettext(POOL), cmd->cmd_tgt1,
1143		    get_errstr());
1144	assoc_list_walk(cmd, pool);
1145}
1146
1147/*
1148 * Assign Commands
1149 * Walk the list of specified assignations so that the required
1150 * components will be assigned to the target resource.
1151 */
1152
1153static void
1154parser_resource_xtransfer(cmd_t *cmd)
1155{
1156	pool_resource_t *resource;
1157
1158	if ((resource = pool_get_resource(conf, PSET, cmd->cmd_tgt1)) == NULL)
1159		die(gettext(ERR_LOCATE_ELEMENT), gettext(RESOURCE),
1160		    cmd->cmd_tgt1, get_errstr());
1161	transfer_list_walk(cmd, resource);
1162}
1163
1164/*
1165 * Transfer Commands
1166 * Transfer the specified quantity of resource between the src and the tgt.
1167 */
1168
1169static void
1170parser_resource_transfer(cmd_t *cmd)
1171{
1172	pool_resource_t *src;
1173	pool_resource_t *tgt;
1174
1175	if ((src = pool_get_resource(conf, PSET, cmd->cmd_tgt1)) == NULL)
1176		die(gettext(ERR_LOCATE_ELEMENT), gettext(RESOURCE),
1177		    cmd->cmd_tgt1, get_errstr());
1178	if ((tgt = pool_get_resource(conf, PSET, cmd->cmd_tgt2)) == NULL)
1179		die(gettext(ERR_LOCATE_ELEMENT), gettext(RESOURCE),
1180		    cmd->cmd_tgt2, get_errstr());
1181	if (pool_resource_transfer(conf, src, tgt, cmd->cmd_qty) != PO_SUCCESS)
1182		die(gettext(ERR_XFER_QUANTITY), cmd->cmd_qty,
1183		    cmd->cmd_tgt1, cmd->cmd_tgt2, get_errstr());
1184}
1185
1186/*
1187 * arg_parse() puts the parser into command parsing mode. Create a tmpfile
1188 * and instruct the parser to read instructions from this location by setting
1189 * yyin to the value returned by tmpfile. Write the command into the file.
1190 * Then seek back to to the start of the file so that the parser can read
1191 * the instructions.
1192 */
1193static void
1194arg_parse(const char *command)
1195{
1196	if ((yyin = tmpfile()) == NULL)
1197		die(gettext(ERR_CMD_FILE_INIT), strerror(errno));
1198	if (fwrite(command, strlen(command), 1, yyin) != 1)
1199		die(gettext(ERR_CMD_FILE_INIT), strerror(errno));
1200	if (fseek(yyin, 0, SEEK_SET) != 0)
1201		die(gettext(ERR_CMD_FILE_INIT), strerror(errno));
1202}
1203
1204/*
1205 * file_parse() puts the parser into command file parsing mode. Firstly check
1206 * to see if the user wishes to parse from standard input, if so do nothing.
1207 * Attempt to open the specified file and instruct the parser to read
1208 * instructions from this location by setting yyin to the value returned by
1209 * fopen.
1210 */
1211static void
1212file_parse(const char *file)
1213{
1214	if (strcmp(file, "-") == 0)
1215		return;
1216
1217	if ((yyin = fopen(file, "r")) == NULL) {
1218		die(gettext(ERR_CMD_FILE_INIT), strerror(errno));
1219	}
1220}
1221
1222/*
1223 * free_cmd() releases the resources associated with the supplied cmd parameter.
1224 */
1225static void
1226free_cmd(cmd_t *cmd)
1227{
1228	prop_t *prop = cmd->cmd_prop_list;
1229	assoc_t *assoc = cmd->cmd_assoc_list;
1230
1231	free((void *)cmd->cmd_tgt1);
1232	free((void *)cmd->cmd_tgt2);
1233	while (prop != NULL) {
1234		prop_t *tmp = prop;
1235		prop = prop->prop_next;
1236		pool_value_free(tmp->prop_value);
1237		free((void *)tmp->prop_name);
1238		free(tmp);
1239	}
1240	while (assoc != NULL) {
1241		assoc_t *tmp = assoc;
1242		assoc = assoc->assoc_next;
1243		free((void *)tmp->assoc_name);
1244		free(tmp);
1245	}
1246	free(cmd);
1247}
1248
1249/*
1250 * alloc_cmd() allocates the required resources for a cmd_t. On failure, a
1251 * warning is issued and NULL is returned.
1252 */
1253static cmd_t *
1254alloc_cmd(void)
1255{
1256	cmd_t *cmd;
1257
1258	if ((cmd = malloc(sizeof (cmd_t))) == NULL) {
1259		warn(gettext(ERR_CMD_LINE_ALLOC));
1260		return (NULL);
1261	}
1262
1263	(void) memset(cmd, 0, sizeof (cmd_t));
1264
1265	return (cmd);
1266}
1267
1268/*
1269 * alloc_prop() allocates the required resources for a prop_t. On failure, a
1270 * warning is issued and NULL is returned. The prop_t is initialised with
1271 * the prop_op_t parameter.
1272 */
1273static prop_t *
1274alloc_prop(prop_op_t op)
1275{
1276	prop_t *prop;
1277
1278	if ((prop = malloc(sizeof (prop_t))) == NULL) {
1279		warn(gettext(ERR_PROP_ALLOC));
1280		return (NULL);
1281	}
1282
1283	(void) memset(prop, 0, sizeof (prop_t));
1284	if ((prop->prop_value = pool_value_alloc()) == NULL) {
1285		warn(gettext(ERR_PROP_ALLOC));
1286		free(prop);
1287		return (NULL);
1288	}
1289	prop->prop_op = op;
1290	return (prop);
1291}
1292
1293/*
1294 * alloc_assoc() allocates the required resources for an assoc_t. On failure, a
1295 * warning is issued and NULL is returned. The assoc_t is initialised with
1296 * the type and name of the association.
1297 */
1298static assoc_t *
1299alloc_assoc(int type, const char *name)
1300{
1301	assoc_t *assoc;
1302
1303	if ((assoc = malloc(sizeof (assoc_t))) == NULL) {
1304		warn(gettext(ERR_ASSOC_ALLOC));
1305		return (NULL);
1306	}
1307	(void) memset(assoc, 0, sizeof (assoc_t));
1308	assoc->assoc_type = type;
1309	assoc->assoc_name = name;
1310	return (assoc);
1311}
1312
1313/*
1314 * check_conf_name() ensures the the name of the system in the configuration
1315 * which is being manipulated matches the name of the system in the command.
1316 * If not, the command is terminated with an appropriate error message.
1317 */
1318static void
1319check_conf_name(cmd_t *cmd)
1320{
1321	pool_value_t *pv;
1322	const char *name;
1323	pool_elem_t *pe;
1324
1325	if ((pe = pool_conf_to_elem(conf)) == NULL)
1326		die(gettext(ERR_GET_ELEMENT_DETAILS),
1327		    gettext(CONFIGURATION), "unknown", get_errstr());
1328
1329
1330	if ((pv = pool_value_alloc()) == NULL) {
1331		die(gettext(ERR_ALLOC_ELEMENT), gettext(RESOURCE),
1332		    get_errstr());
1333	}
1334
1335	if (pool_get_property(conf, pe, SYSTEM_NAME, pv)
1336	    == POC_INVAL)
1337		die(gettext(ERR_GET_PROPERTY), gettext(SYSTEM_NAME),
1338		    get_errstr());
1339
1340	if (pool_value_get_string(pv, &name) == PO_FAIL)
1341		die(gettext(ERR_GET_PROPERTY), gettext(SYSTEM_NAME),
1342		    get_errstr());
1343
1344	if (strcmp(cmd->cmd_tgt1, name) != 0) {
1345		die(gettext(ERR_WRONG_SYSTEM_NAME), cmd->cmd_tgt1);
1346	}
1347	pool_value_free(pv);
1348}
1349
1350/*
1351 * usage() display brief or verbose help for the poolcfg(1) command.
1352 */
1353static void
1354usage(int help)
1355{
1356	if (help >= 1)
1357		(void) fprintf(stderr, gettext(USAGE1), cmdname, cmdname,
1358		    cmdname);
1359	if (help >= 2)
1360		(void) fprintf(stderr, gettext(USAGE2));
1361	exit(E_USAGE);
1362}
1363
1364/*
1365 * prop_list_walk() walks the property manipulation requests and either puts
1366 * or removes the property as appropriate.
1367 */
1368static void
1369prop_list_walk(cmd_t *cmd, pool_elem_t *pe)
1370{
1371	prop_t *prop;
1372
1373	for (prop = cmd->cmd_prop_list; prop != NULL; prop = prop->prop_next) {
1374		switch (prop->prop_op) {
1375		case po_create:
1376			if (pool_put_property(conf, pe, prop->prop_name,
1377			    prop->prop_value) != 0)
1378				die(gettext(ERR_PUT_PROPERTY),
1379				    prop->prop_name, get_errstr());
1380			break;
1381		case po_remove:
1382			if (pool_rm_property(conf, pe, prop->prop_name) != 0)
1383				die(gettext(ERR_REMOVE_PROPERTY),
1384				    prop->prop_name, get_errstr());
1385			break;
1386		}
1387	}
1388}
1389
1390/*
1391 * assoc_list_walk() walks the resource association requests and attempts
1392 * to associate the pool with the specified resource.
1393 */
1394static void
1395assoc_list_walk(cmd_t *cmd, pool_t *pool)
1396{
1397	assoc_t *assoc;
1398
1399	for (assoc = cmd->cmd_assoc_list; assoc != NULL;
1400	    assoc = assoc->assoc_next) {
1401		pool_resource_t *resource;
1402
1403		switch (assoc->assoc_type) {
1404		case PCE_PSET:
1405			if ((resource = pool_get_resource(conf,
1406			    PSET, assoc->assoc_name)) == NULL)
1407				die(gettext(ERR_LOCATE_ELEMENT), gettext(PSET),
1408				    assoc->assoc_name, get_errstr());
1409			break;
1410		default:
1411			die(gettext(ERR_UNKNOWN_RESOURCE),
1412			    assoc->assoc_type);
1413			break;
1414		}
1415		if (pool_associate(conf, pool, resource) != 0)
1416			die(gettext(ERR_ASSOC_RESOURCE), assoc->assoc_name,
1417			    get_errstr());
1418	}
1419}
1420
1421/*
1422 * transfer_list_walk() walks the component assign requests and attempts
1423 * to assign the component with the specified resource.
1424 */
1425static void
1426transfer_list_walk(cmd_t *cmd, pool_resource_t *tgt)
1427{
1428	assoc_t *assoc;
1429
1430	for (assoc = cmd->cmd_assoc_list; assoc != NULL;
1431	    assoc = assoc->assoc_next) {
1432		pool_component_t *comp;
1433		pool_resource_t *src;
1434		pool_component_t *xfer[2] = {NULL};
1435
1436		if ((comp = get_cpu(assoc->assoc_name)) == NULL)
1437			die(gettext(ERR_LOCATE_ELEMENT), gettext(CPU),
1438			    assoc->assoc_name, get_errstr());
1439		if ((src = pool_get_owning_resource(conf, comp)) == NULL)
1440			die(gettext(ERR_XFER_COMPONENT), gettext(COMPONENT),
1441			    assoc->assoc_name, cmd->cmd_tgt1, get_errstr());
1442		xfer[0] = comp;
1443		if (pool_resource_xtransfer(conf, src, tgt, xfer) !=
1444		    PO_SUCCESS)
1445			die(gettext(ERR_XFER_COMPONENT), gettext(COMPONENT),
1446			    assoc->assoc_name, cmd->cmd_tgt1, get_errstr());
1447	}
1448}
1449
1450/*
1451 * terminate() is invoked when poolcfg exits. It cleans up
1452 * configurations and closes the parser input stream.
1453 */
1454static void
1455terminate(void)
1456{
1457	if (conf != NULL) {
1458		(void) pool_conf_close(conf);
1459		pool_conf_free(conf);
1460	}
1461	if (yyin != stdin)
1462		(void) fclose(yyin);
1463}
1464
1465/*
1466 * get_cpu() takes the name of a CPU components and attempts to locate
1467 * the element with that name. If the name is not formatted correctly
1468 * (i.e. contains non-numeric characters) then the function terminates
1469 * execution. If the components cannot be uniquely identified by the
1470 * name, then NULL is returned.
1471 */
1472static pool_component_t *
1473get_cpu(const char *name)
1474{
1475	pool_component_t **components;
1476	uint_t nelem;
1477	int64_t sysid;
1478	pool_value_t *vals[3] = {NULL};
1479	pool_component_t *ret;
1480	const char *c;
1481
1482	if ((vals[0] = pool_value_alloc()) == NULL)
1483		return (NULL);
1484	if ((vals[1] = pool_value_alloc()) == NULL) {
1485		pool_value_free(vals[0]);
1486		return (NULL);
1487	}
1488	if (pool_value_set_string(vals[0], "cpu") != PO_SUCCESS ||
1489	    pool_value_set_name(vals[0], "type") != PO_SUCCESS) {
1490		pool_value_free(vals[0]);
1491		pool_value_free(vals[1]);
1492		return (NULL);
1493	}
1494
1495	for (c = name; *c != '\0'; c++) {
1496		if (!isdigit(*c)){
1497			pool_value_free(vals[0]);
1498			pool_value_free(vals[1]);
1499			die(gettext(ERR_LOCATE_ELEMENT), gettext(CPU),
1500			    cmd->cmd_tgt1, gettext("CPU id should only contain "
1501			    "digits"));
1502		}
1503	}
1504	sysid = strtoll(name, NULL, 0);
1505	if (errno == ERANGE || errno == EINVAL) {
1506		pool_value_free(vals[0]);
1507		pool_value_free(vals[1]);
1508		return (NULL);
1509	}
1510	pool_value_set_int64(vals[1], sysid);
1511	if (pool_value_set_name(vals[1], CPU_SYSID) != PO_SUCCESS) {
1512		pool_value_free(vals[0]);
1513		pool_value_free(vals[1]);
1514		return (NULL);
1515	}
1516	if ((components = pool_query_components(conf, &nelem, vals)) ==
1517	    NULL) {
1518		pool_value_free(vals[0]);
1519		pool_value_free(vals[1]);
1520		return (NULL);
1521	}
1522	if (nelem != 1) {
1523		free(components);
1524		pool_value_free(vals[0]);
1525		pool_value_free(vals[1]);
1526		return (NULL);
1527	}
1528	pool_value_free(vals[0]);
1529	pool_value_free(vals[1]);
1530	ret = components[0];
1531	free(components);
1532	return (ret);
1533}
1534
1535/*
1536 * process_min_max() ensures that "min" and "max" properties are
1537 * processed correctly by poolcfg. libpool enforces validity
1538 * constraints on these properties and so it's important that changes
1539 * to them are supplied to the library in the correct order.
1540 */
1541void
1542process_min_max(pool_resource_t *resource)
1543{
1544	prop_t *minprop = NULL;
1545	prop_t *maxprop = NULL;
1546	prop_t *prop;
1547
1548	/*
1549	 * Before walking the list of properties, it has to be checked
1550	 * to ensure there are no clashes between min and max. If
1551	 * there are, then process these properties immediately.
1552	 */
1553	for (prop = cmd->cmd_prop_list; prop != NULL; prop = prop->prop_next) {
1554		const char *pos;
1555
1556		if ((pos = strstr(prop->prop_name, min_suffix)) != NULL)
1557			if (pos == prop->prop_name + strlen(prop->prop_name)
1558			    - 4)
1559				minprop = prop;
1560		if ((pos = strstr(prop->prop_name, max_suffix)) != NULL)
1561			if (pos == prop->prop_name + strlen(prop->prop_name)
1562			    - 4)
1563				maxprop = prop;
1564	}
1565	if (minprop && maxprop) {
1566		pool_value_t *pv;
1567		uint64_t smin, smax, dmax;
1568		const char *type;
1569		char *prop_name;
1570		pool_elem_t *pe = pool_resource_to_elem(conf, resource);
1571
1572		if ((pv = pool_value_alloc()) == NULL)
1573			die(gettext(ERR_NOMEM));
1574
1575		(void) pool_get_property(conf, pe, "type", pv);
1576		(void) pool_value_get_string(pv, &type);
1577
1578		if ((prop_name = malloc(strlen(type) + strlen(max_suffix)
1579		    + 1)) == NULL)
1580			die(gettext(ERR_NOMEM));
1581
1582		(void) sprintf(prop_name, "%s%s", type, max_suffix);
1583		(void) pool_get_property(conf, pe, prop_name, pv);
1584		(void) pool_value_get_uint64(pv, &dmax);
1585
1586		(void) pool_value_get_uint64(minprop->prop_value, &smin);
1587
1588		(void) pool_value_get_uint64(maxprop->prop_value, &smax);
1589		if (smin < dmax) {
1590			(void) pool_put_property(conf, pe,
1591			minprop->prop_name, minprop->prop_value);
1592		} else {
1593			(void) pool_put_property(conf, pe,
1594			maxprop->prop_name, maxprop->prop_value);
1595		}
1596		free((void *)prop_name);
1597		pool_value_free(pv);
1598	}
1599}
1600