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