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