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