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
parser_conf_info(cmd_t * cmd)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
parser_pool_info(cmd_t * cmd)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
parser_resource_info(cmd_t * cmd,const char * type)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
parser_pset_info(cmd_t * cmd)846 parser_pset_info(cmd_t *cmd)
847 {
848 parser_resource_info(cmd, PSET);
849 }
850
851 static void
parser_cpu_info(cmd_t * cmd)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
parser_conf_create(cmd_t * cmd)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
parser_pool_create(cmd_t * cmd)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
parser_resource_create(cmd_t * cmd,const char * type)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
parser_pset_create(cmd_t * cmd)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
parser_rename(cmd_t * cmd,pool_elem_t * pe,const char * name)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
parser_conf_rename(cmd_t * cmd)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
parser_pool_rename(cmd_t * cmd)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
parser_pset_rename(cmd_t * cmd)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
parser_conf_destroy(cmd_t * cmd)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
parser_pool_destroy(cmd_t * cmd)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
parser_resource_destroy(cmd_t * cmd,const char * type)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
parser_pset_destroy(cmd_t * cmd)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
parser_conf_modify(cmd_t * cmd)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
parser_pool_modify(cmd_t * cmd)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
parser_resource_modify(cmd_t * cmd,const char * type)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
parser_pset_modify(cmd_t * cmd)1080 parser_pset_modify(cmd_t *cmd)
1081 {
1082 parser_resource_modify(cmd, PSET);
1083 }
1084
1085 static void
parser_cpu_modify(cmd_t * cmd)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
parser_conf_discover(cmd_t * cmd)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
parser_pool_associate(cmd_t * cmd)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
parser_resource_xtransfer(cmd_t * cmd)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
parser_resource_transfer(cmd_t * cmd)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
arg_parse(const char * command)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
file_parse(const char * file)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
free_cmd(cmd_t * cmd)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 *
alloc_cmd(void)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 *
alloc_prop(prop_op_t op)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 *
alloc_assoc(int type,const char * name)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
check_conf_name(cmd_t * cmd)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
usage(int help)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
prop_list_walk(cmd_t * cmd,pool_elem_t * pe)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
assoc_list_walk(cmd_t * cmd,pool_t * pool)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
transfer_list_walk(cmd_t * cmd,pool_resource_t * tgt)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
terminate(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 *
get_cpu(const char * name)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
process_min_max(pool_resource_t * resource)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