xref: /illumos-gate/usr/src/cmd/pools/poolcfg/poolcfg.y (revision 4224cf35431a1b80d14862409ecf0beeaa49e0d8)
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 
113 int dofile = PO_FALSE;			/* poolcfg.l uses this for errors */
114 int conf_edit_error = POE_OK;		/* cached error for error reporting */
115 int conf_edit_errno = 0;		/* cached errno for error reporting */
116 int conf_list_error = POE_OK;		/* cached error for error reporting */
117 int conf_list_errno = 0;		/* cached errno for error reporting */
118 static const char cmdname[] = "poolcfg";
119 static const char cmd_options[] = "c:df:h";
120 static void usage(int);
121 static const char *max_suffix = ".max";
122 static const char *min_suffix = ".min";
123 
124 static const char *conf_file = NULL;	/* Location of target config */
125 static cmd_t *cmd = NULL;		/* Command being processed */
126 static pool_conf_t *conf = NULL;	/* Config to be processed */
127 static int edited = PO_FALSE;		/* Has the configuration been changed */
128 
129 /* yacc externals */
130 extern FILE *yyin;
131 extern int yydebug;
132 extern void yyerror(char *s);
133 
134 /* Utility functions */
135 static void arg_parse(const char *);
136 static void file_parse(const char *);
137 static cmd_t *alloc_cmd(void);
138 static prop_t *alloc_prop(prop_op_t);
139 static assoc_t *alloc_assoc(int, const char *);
140 static void free_cmd(cmd_t *);
141 static void check_conf_name(cmd_t *);
142 static void prop_list_walk(cmd_t *, pool_elem_t *);
143 static void assoc_list_walk(cmd_t *, pool_t *);
144 static void transfer_list_walk(cmd_t *, pool_resource_t *);
145 static void terminate(void);
146 static pool_component_t *get_cpu(const char *);
147 static void process_min_max(pool_resource_t *);
148 
149 /* Info Commands */
150 static void parser_conf_info(cmd_t *);
151 static void parser_pool_info(cmd_t *);
152 static void parser_resource_info(cmd_t *, const char *);
153 static void parser_pset_info(cmd_t *);
154 static void parser_cpu_info(cmd_t *);
155 
156 /* Create Commands */
157 static void parser_conf_create(cmd_t *);
158 static void parser_pool_create(cmd_t *);
159 static void parser_resource_create(cmd_t *, const char *);
160 static void parser_pset_create(cmd_t *);
161 
162 /* Destroy Commands */
163 static void parser_conf_destroy(cmd_t *);
164 static void parser_pool_destroy(cmd_t *);
165 static void parser_resource_destroy(cmd_t *, const char *);
166 static void parser_pset_destroy(cmd_t *);
167 
168 /* Modify Commands */
169 static void parser_conf_modify(cmd_t *);
170 static void parser_pool_modify(cmd_t *);
171 static void parser_resource_modify(cmd_t *, const char *);
172 static void parser_pset_modify(cmd_t *);
173 static void parser_cpu_modify(cmd_t *);
174 
175 /* Associate Commands */
176 static void parser_pool_associate(cmd_t *);
177 
178 /* Assign Commands */
179 static void parser_resource_xtransfer(cmd_t *);
180 static void parser_resource_transfer(cmd_t *);
181 
182 /* Discover Commands */
183 static void parser_conf_discover(cmd_t *);
184 
185 /* Rename Commands */
186 static void parser_rename(cmd_t *, pool_elem_t *, const char *);
187 static void parser_conf_rename(cmd_t *);
188 static void parser_pool_rename(cmd_t *);
189 static 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
211 PCK_COMMAND
212 %token PCV_FILENAME PCV_SYMBOL PCV_VAL_INT PCV_VAL_UINT PCV_VAL_FLOAT
213 PCV_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
231 destroy_command modify_command associate_command discover_command
232 rename_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 
241 commands: 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 
255 command: 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 
269 list_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 
282 edit_command: create_command
283 	| destroy_command
284 	| modify_command
285 	| associate_command
286 	| transfer_command
287 	| rename_command;
288 
289 info_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 
321 create_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 
349 destroy_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 
371 modify_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 
397 associate_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 
407 transfer_command: transfer_qty
408 	| transfer_components;
409 
410 transfer_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 
420 transfer_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 
441 discover_command: PCC_DISC
442 	{
443 		if (($$ = alloc_cmd()) == NULL)
444 			YYERROR;
445 		cmd = $$;
446 		$$->cmd = &parser_conf_discover;
447 	};
448 
449 rename_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 
472 modify_entity: entity
473 	| PCE_CPU  {$$ = PCE_CPU;};
474 
475 info_entity: entity
476 	| PCE_CPU  {$$ = PCE_CPU;};
477 
478 entity: PCE_SYSTEM {$$ = PCE_SYSTEM;}
479 	| PCE_POOL {$$ = PCE_POOL;}
480 	| PCE_PSET {$$ = PCE_PSET;};
481 
482 name: PCV_SYMBOL;
483 
484 src: PCV_SYMBOL;
485 
486 tgt: PCV_SYMBOL;
487 
488 value: 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 
494 prop_remove: PCK_UNDEF proptype name
495 	{
496 		if (($$ = alloc_prop(po_remove)) == NULL)
497 			YYERROR;
498 		$$->prop_name = $3;
499 	};
500 
501 prop_op: prop_assign
502 	| prop_remove;
503 
504 prop_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 
534 prop_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 
558 property_list: PCK_OPENLST prop_ops PCK_CLOSELST
559 	{
560 		$$ = $2;
561 	};
562 
563 resource_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 
591 resource_assign: resource name
592 	{
593 		if (($$ = alloc_assoc($1, $2)) == NULL)
594 			YYERROR;
595 	};
596 
597 resource: PCE_PSET {$$ = PCE_PSET;};
598 
599 resource_list: PCK_OPENLST resource_assigns PCK_CLOSELST
600 	{
601 		$$ = $2;
602 	};
603 
604 component_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 
632 component_list: PCK_OPENLST component_assigns PCK_CLOSELST
633 	{
634 		$$ = $2;
635 	};
636 
637 component_assign: component name
638 	{
639 		if (($$ = alloc_assoc($1, $2)) == NULL)
640 			YYERROR;
641 	};
642 
643 component: PCE_CPU {$$ = PCE_CPU;};
644 
645 proptype: 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 
657 int
658 main(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  */
774 static void
775 parser_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 
809 static void
810 parser_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 
826 static void
827 parser_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 
843 static void
844 parser_pset_info(cmd_t *cmd)
845 {
846 	parser_resource_info(cmd, PSET);
847 }
848 
849 static void
850 parser_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  */
871 static void
872 parser_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 
893 static void
894 parser_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 
904 static void
905 parser_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 
919 static void
920 parser_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  */
929 static void
930 parser_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 
944 static void
945 parser_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 
959 static void
960 parser_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 
971 static void
972 parser_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  */
988 static void
989 parser_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 
999 static void
1000 parser_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 
1013 static void
1014 parser_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 
1027 static void
1028 parser_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  */
1037 static void
1038 parser_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 
1052 static void
1053 parser_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 
1063 static void
1064 parser_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 
1077 static void
1078 parser_pset_modify(cmd_t *cmd)
1079 {
1080 	parser_resource_modify(cmd, PSET);
1081 }
1082 
1083 static void
1084 parser_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*/
1101 static void
1102 parser_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 
1136 static void
1137 parser_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 
1153 static void
1154 parser_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 
1169 static void
1170 parser_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  */
1193 static void
1194 arg_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  */
1211 static void
1212 file_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  */
1225 static void
1226 free_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  */
1253 static cmd_t *
1254 alloc_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  */
1273 static prop_t *
1274 alloc_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  */
1298 static assoc_t *
1299 alloc_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  */
1318 static void
1319 check_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  */
1353 static void
1354 usage(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  */
1368 static void
1369 prop_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  */
1394 static void
1395 assoc_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  */
1425 static void
1426 transfer_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  */
1454 static void
1455 terminate(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  */
1472 static pool_component_t *
1473 get_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  */
1541 void
1542 process_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