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 void yyerror(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 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 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 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 844 parser_pset_info(cmd_t *cmd) 845 { 846 parser_resource_info(cmd, PSET); 847 } 848 849 static void 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 1078 parser_pset_modify(cmd_t *cmd) 1079 { 1080 parser_resource_modify(cmd, PSET); 1081 } 1082 1083 static void 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 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 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 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 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 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 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 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 * 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 * 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 * 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 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 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 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 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 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 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 * 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 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