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