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