1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2007 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 #include <assert.h> 30 #include <errno.h> 31 #include <libintl.h> 32 #include <libuutil.h> 33 #include <stdarg.h> 34 #include <stddef.h> 35 #include <string.h> 36 37 #include "svccfg.h" 38 39 /* 40 * Internal representation manipulation routines for svccfg(1) 41 */ 42 43 static uu_list_pool_t *entity_pool; 44 static uu_list_pool_t *pgroup_pool; 45 static uu_list_pool_t *property_pool; 46 static uu_list_pool_t *value_pool; 47 48 /* ARGSUSED */ 49 static int 50 entity_cmp(const void *a, const void *b, void *p) 51 { 52 entity_t *A = (entity_t *)a; 53 entity_t *B = (entity_t *)b; 54 55 return (strcmp(A->sc_name, B->sc_name)); 56 } 57 58 /*ARGSUSED*/ 59 static int 60 pgroup_cmp(const void *a, const void *b, void *p) 61 { 62 pgroup_t *A = (pgroup_t *)a; 63 pgroup_t *B = (pgroup_t *)b; 64 65 return (strcmp(A->sc_pgroup_name, B->sc_pgroup_name)); 66 } 67 68 /* ARGSUSED */ 69 static int 70 property_cmp(const void *a, const void *b, void *p) 71 { 72 property_t *A = (property_t *)a; 73 property_t *B = (property_t *)b; 74 75 return (strcmp(A->sc_property_name, B->sc_property_name)); 76 } 77 78 /* ARGSUSED */ 79 int 80 value_cmp(const void *a, const void *b, void *p) 81 { 82 const value_t *A = a; 83 const value_t *B = b; 84 85 if (A->sc_type != B->sc_type) 86 return (B->sc_type - A->sc_type); 87 88 switch (A->sc_type) { 89 case SCF_TYPE_BOOLEAN: 90 case SCF_TYPE_COUNT: 91 return (B->sc_u.sc_count - A->sc_u.sc_count); 92 93 case SCF_TYPE_INTEGER: 94 return (B->sc_u.sc_integer - A->sc_u.sc_integer); 95 96 default: 97 return (strcmp(A->sc_u.sc_string, B->sc_u.sc_string)); 98 } 99 } 100 101 void 102 internal_init() 103 { 104 if ((entity_pool = uu_list_pool_create("entities", sizeof (entity_t), 105 offsetof(entity_t, sc_node), entity_cmp, 0)) == NULL) 106 uu_die(gettext("entity list pool creation failed: %s\n"), 107 uu_strerror(uu_error())); 108 109 if ((pgroup_pool = uu_list_pool_create("property_groups", 110 sizeof (pgroup_t), offsetof(pgroup_t, sc_node), pgroup_cmp, 0)) == 111 NULL) 112 uu_die( 113 gettext("property group list pool creation failed: %s\n"), 114 uu_strerror(uu_error())); 115 116 if ((property_pool = uu_list_pool_create("properties", 117 sizeof (property_t), offsetof(property_t, sc_node), property_cmp, 118 0)) == NULL) 119 uu_die(gettext("property list pool creation failed: %s\n"), 120 uu_strerror(uu_error())); 121 122 if ((value_pool = uu_list_pool_create("property_values", 123 sizeof (value_t), offsetof(value_t, sc_node), value_cmp, 0)) == 124 NULL) 125 uu_die( 126 gettext("property value list pool creation failed: %s\n"), 127 uu_strerror(uu_error())); 128 } 129 130 /*ARGSUSED*/ 131 static int 132 internal_value_dump(void *v, void *pvt) 133 { 134 value_t *val = v; 135 136 switch (val->sc_type) { 137 case SCF_TYPE_BOOLEAN: 138 (void) printf(" value = %s\n", 139 val->sc_u.sc_count ? "true" : "false"); 140 break; 141 case SCF_TYPE_COUNT: 142 (void) printf(" value = %llu\n", val->sc_u.sc_count); 143 break; 144 case SCF_TYPE_INTEGER: 145 (void) printf(" value = %lld\n", val->sc_u.sc_integer); 146 break; 147 case SCF_TYPE_ASTRING: 148 case SCF_TYPE_FMRI: 149 case SCF_TYPE_HOST: 150 case SCF_TYPE_HOSTNAME: 151 case SCF_TYPE_NET_ADDR_V4: 152 case SCF_TYPE_NET_ADDR_V6: 153 case SCF_TYPE_OPAQUE: 154 case SCF_TYPE_TIME: 155 case SCF_TYPE_URI: 156 case SCF_TYPE_USTRING: 157 (void) printf(" value = %s\n", 158 val->sc_u.sc_string ? val->sc_u.sc_string : "(nil)"); 159 break; 160 default: 161 uu_die(gettext("unknown value type (%d)\n"), val->sc_type); 162 break; 163 } 164 165 return (UU_WALK_NEXT); 166 } 167 168 /*ARGSUSED*/ 169 static int 170 internal_property_dump(void *v, void *pvt) 171 { 172 property_t *p = v; 173 174 (void) printf("property\n name = %s\n", p->sc_property_name); 175 (void) printf(" type = %d\n", p->sc_value_type); 176 177 (void) uu_list_walk(p->sc_property_values, internal_value_dump, 178 NULL, UU_DEFAULT); 179 180 return (UU_WALK_NEXT); 181 } 182 183 /*ARGSUSED*/ 184 static int 185 internal_pgroup_dump(void *v, void *pvt) 186 { 187 pgroup_t *pg = v; 188 189 (void) printf("pgroup name = %s\n", pg->sc_pgroup_name); 190 (void) printf(" type = %s\n", pg->sc_pgroup_type); 191 192 (void) uu_list_walk(pg->sc_pgroup_props, internal_property_dump, 193 NULL, UU_DEFAULT); 194 195 return (UU_WALK_NEXT); 196 } 197 198 /*ARGSUSED*/ 199 static int 200 internal_instance_dump(void *v, void *pvt) 201 { 202 entity_t *i = v; 203 204 (void) printf("instance name = %s\n", i->sc_name); 205 206 (void) uu_list_walk(i->sc_pgroups, internal_pgroup_dump, NULL, 207 UU_DEFAULT); 208 209 return (UU_WALK_NEXT); 210 } 211 212 /*ARGSUSED*/ 213 static int 214 internal_service_dump(void *v, void *pvt) 215 { 216 entity_t *s = v; 217 218 (void) printf("service name = %s\n", s->sc_name); 219 (void) printf(" type = %x\n", s->sc_u.sc_service.sc_service_type); 220 (void) printf(" version = %u\n", s->sc_u.sc_service.sc_service_version); 221 222 (void) uu_list_walk(s->sc_pgroups, internal_pgroup_dump, NULL, 223 UU_DEFAULT); 224 225 (void) uu_list_walk(s->sc_u.sc_service.sc_service_instances, 226 internal_instance_dump, NULL, UU_DEFAULT); 227 228 return (UU_WALK_NEXT); 229 } 230 231 void 232 internal_dump(bundle_t *b) 233 { 234 (void) printf("bundle name = %s\n", b->sc_bundle_name); 235 (void) printf(" type = %x\n", b->sc_bundle_type); 236 237 (void) uu_list_walk(b->sc_bundle_services, internal_service_dump, 238 NULL, UU_DEFAULT); 239 } 240 241 bundle_t * 242 internal_bundle_new() 243 { 244 bundle_t *b; 245 246 if ((b = uu_zalloc(sizeof (bundle_t))) == NULL) 247 uu_die(gettext("couldn't allocate memory")); 248 249 b->sc_bundle_type = SVCCFG_UNKNOWN_BUNDLE; 250 b->sc_bundle_services = uu_list_create(entity_pool, b, 0); 251 252 return (b); 253 } 254 255 void 256 internal_bundle_free(bundle_t *b) 257 { 258 void *cookie = NULL; 259 entity_t *service; 260 261 while ((service = uu_list_teardown(b->sc_bundle_services, &cookie)) != 262 NULL) 263 internal_service_free(service); 264 265 free(b); 266 } 267 268 entity_t * 269 internal_service_new(const char *name) 270 { 271 entity_t *s; 272 273 if ((s = uu_zalloc(sizeof (entity_t))) == NULL) 274 uu_die(gettext("couldn't allocate memory")); 275 276 uu_list_node_init(s, &s->sc_node, entity_pool); 277 278 s->sc_name = name; 279 s->sc_fmri = uu_msprintf("svc:/%s", name); 280 if (s->sc_fmri == NULL) 281 uu_die(gettext("couldn't allocate memory")); 282 283 s->sc_etype = SVCCFG_SERVICE_OBJECT; 284 s->sc_pgroups = uu_list_create(pgroup_pool, s, 0); 285 s->sc_dependents = uu_list_create(pgroup_pool, s, 0); 286 287 s->sc_u.sc_service.sc_service_type = SVCCFG_UNKNOWN_SERVICE; 288 s->sc_u.sc_service.sc_service_instances = uu_list_create(entity_pool, s, 289 0); 290 291 return (s); 292 } 293 294 void 295 internal_service_free(entity_t *s) 296 { 297 entity_t *inst; 298 pgroup_t *pg; 299 void *cookie; 300 301 cookie = NULL; 302 while ((pg = uu_list_teardown(s->sc_pgroups, &cookie)) != NULL) 303 internal_pgroup_free(pg); 304 305 cookie = NULL; 306 while ((pg = uu_list_teardown(s->sc_dependents, &cookie)) != NULL) 307 internal_pgroup_free(pg); 308 309 cookie = NULL; 310 while ((inst = uu_list_teardown(s->sc_u.sc_service.sc_service_instances, 311 &cookie)) != NULL) 312 internal_instance_free(inst); 313 314 free(s); 315 } 316 317 entity_t * 318 internal_instance_new(const char *name) 319 { 320 entity_t *i; 321 322 if ((i = uu_zalloc(sizeof (entity_t))) == NULL) 323 uu_die(gettext("couldn't allocate memory")); 324 325 uu_list_node_init(i, &i->sc_node, entity_pool); 326 327 i->sc_name = name; 328 /* Can't set i->sc_fmri until we're attached to a service. */ 329 i->sc_etype = SVCCFG_INSTANCE_OBJECT; 330 i->sc_pgroups = uu_list_create(pgroup_pool, i, 0); 331 i->sc_dependents = uu_list_create(pgroup_pool, i, 0); 332 333 return (i); 334 } 335 336 void 337 internal_instance_free(entity_t *i) 338 { 339 pgroup_t *pg; 340 void *cookie = NULL; 341 342 while ((pg = uu_list_teardown(i->sc_pgroups, &cookie)) != NULL) 343 internal_pgroup_free(pg); 344 345 cookie = NULL; 346 while ((pg = uu_list_teardown(i->sc_dependents, &cookie)) != NULL) 347 internal_pgroup_free(pg); 348 349 free(i); 350 } 351 352 entity_t * 353 internal_template_new() 354 { 355 entity_t *t; 356 357 if ((t = uu_zalloc(sizeof (entity_t))) == NULL) 358 uu_die(gettext("couldn't allocate memory")); 359 360 uu_list_node_init(t, &t->sc_node, entity_pool); 361 362 t->sc_etype = SVCCFG_TEMPLATE_OBJECT; 363 t->sc_pgroups = uu_list_create(pgroup_pool, t, 0); 364 365 return (t); 366 } 367 368 pgroup_t * 369 internal_pgroup_new() 370 { 371 pgroup_t *p; 372 373 if ((p = uu_zalloc(sizeof (pgroup_t))) == NULL) 374 uu_die(gettext("couldn't allocate memory")); 375 376 uu_list_node_init(p, &p->sc_node, pgroup_pool); 377 378 p->sc_pgroup_props = uu_list_create(property_pool, p, UU_LIST_SORTED); 379 p->sc_pgroup_name = "<unset>"; 380 p->sc_pgroup_type = "<unset>"; 381 382 return (p); 383 } 384 385 void 386 internal_pgroup_free(pgroup_t *pg) 387 { 388 property_t *prop; 389 void *cookie = NULL; 390 391 while ((prop = uu_list_teardown(pg->sc_pgroup_props, &cookie)) != NULL) 392 internal_property_free(prop); 393 394 uu_free(pg); 395 } 396 397 static pgroup_t * 398 find_pgroup(uu_list_t *list, const char *name, const char *type) 399 { 400 pgroup_t *pg; 401 402 for (pg = uu_list_first(list); 403 pg != NULL; 404 pg = uu_list_next(list, pg)) { 405 if (strcmp(pg->sc_pgroup_name, name) != 0) 406 continue; 407 408 if (type == NULL) 409 return (pg); 410 411 if (strcmp(pg->sc_pgroup_type, type) == 0) 412 return (pg); 413 } 414 415 return (NULL); 416 } 417 418 pgroup_t * 419 internal_dependent_find(entity_t *e, const char *name) 420 { 421 return (find_pgroup(e->sc_dependents, name, NULL)); 422 } 423 424 pgroup_t * 425 internal_pgroup_find(entity_t *e, const char *name, const char *type) 426 { 427 return (find_pgroup(e->sc_pgroups, name, type)); 428 } 429 430 pgroup_t * 431 internal_pgroup_find_or_create(entity_t *e, const char *name, const char *type) 432 { 433 pgroup_t *pg; 434 435 pg = internal_pgroup_find(e, name, type); 436 if (pg != NULL) 437 return (pg); 438 439 pg = internal_pgroup_new(); 440 (void) internal_attach_pgroup(e, pg); 441 pg->sc_pgroup_name = strdup(name); 442 pg->sc_pgroup_type = strdup(type); 443 pg->sc_pgroup_flags = 0; 444 445 if (pg->sc_pgroup_name == NULL || pg->sc_pgroup_type == NULL) 446 uu_die(gettext("Could not duplicate string")); 447 448 return (pg); 449 } 450 451 property_t * 452 internal_property_new() 453 { 454 property_t *p; 455 456 if ((p = uu_zalloc(sizeof (property_t))) == NULL) 457 uu_die(gettext("couldn't allocate memory")); 458 459 uu_list_node_init(p, &p->sc_node, property_pool); 460 461 p->sc_property_values = uu_list_create(value_pool, p, UU_LIST_SORTED); 462 p->sc_property_name = "<unset>"; 463 464 return (p); 465 } 466 467 void 468 internal_property_free(property_t *p) 469 { 470 value_t *val; 471 void *cookie = NULL; 472 473 while ((val = uu_list_teardown(p->sc_property_values, &cookie)) != 474 NULL) { 475 if (val->sc_free != NULL) 476 val->sc_free(val); 477 free(val); 478 } 479 480 free(p); 481 } 482 483 property_t * 484 internal_property_find(pgroup_t *pg, const char *name) 485 { 486 property_t *p; 487 488 for (p = uu_list_first(pg->sc_pgroup_props); 489 p != NULL; 490 p = uu_list_next(pg->sc_pgroup_props, p)) 491 if (strcmp(p->sc_property_name, name) == 0) 492 return (p); 493 494 return (NULL); 495 } 496 497 value_t * 498 internal_value_new() 499 { 500 value_t *v; 501 502 if ((v = uu_zalloc(sizeof (value_t))) == NULL) 503 uu_die(gettext("couldn't allocate memory")); 504 505 uu_list_node_init(v, &v->sc_node, value_pool); 506 507 return (v); 508 } 509 510 static void 511 internal_value_free_str(value_t *v) 512 { 513 free(v->sc_u.sc_string); 514 } 515 516 property_t * 517 internal_property_create(const char *name, scf_type_t vtype, uint_t nvals, ...) 518 { 519 va_list args; 520 property_t *p; 521 value_t *v; 522 523 p = internal_property_new(); 524 525 p->sc_property_name = (char *)name; 526 p->sc_value_type = vtype; 527 528 va_start(args, nvals); 529 for (; nvals > 0; nvals--) { 530 531 v = internal_value_new(); 532 v->sc_type = vtype; 533 534 switch (vtype) { 535 case SCF_TYPE_BOOLEAN: 536 case SCF_TYPE_COUNT: 537 v->sc_u.sc_count = va_arg(args, uint64_t); 538 break; 539 case SCF_TYPE_INTEGER: 540 v->sc_u.sc_integer = va_arg(args, int64_t); 541 break; 542 case SCF_TYPE_ASTRING: 543 case SCF_TYPE_FMRI: 544 case SCF_TYPE_HOST: 545 case SCF_TYPE_HOSTNAME: 546 case SCF_TYPE_NET_ADDR_V4: 547 case SCF_TYPE_NET_ADDR_V6: 548 case SCF_TYPE_OPAQUE: 549 case SCF_TYPE_TIME: 550 case SCF_TYPE_URI: 551 case SCF_TYPE_USTRING: 552 v->sc_u.sc_string = (char *)va_arg(args, uchar_t *); 553 break; 554 default: 555 va_end(args); 556 uu_die(gettext("unknown property type (%d)\n"), vtype); 557 break; 558 } 559 560 internal_attach_value(p, v); 561 } 562 va_end(args); 563 564 return (p); 565 } 566 567 /* 568 * Some of these attach functions use uu_list_append() to maintain the 569 * same order across import/export, whereas others are always sorted 570 * anyway, or the order is irrelevant. 571 */ 572 573 int 574 internal_attach_service(bundle_t *bndl, entity_t *svc) 575 { 576 if (uu_list_find(bndl->sc_bundle_services, svc, NULL, NULL) != NULL) { 577 semerr(gettext("Multiple definitions for service %s in " 578 "bundle %s.\n"), svc->sc_name, bndl->sc_bundle_name); 579 return (-1); 580 } 581 582 (void) uu_list_append(bndl->sc_bundle_services, svc); 583 584 return (0); 585 } 586 587 int 588 internal_attach_entity(entity_t *svc, entity_t *ent) 589 { 590 if (ent->sc_etype == SVCCFG_TEMPLATE_OBJECT) { 591 svc->sc_u.sc_service.sc_service_template = ent; 592 return (0); 593 } 594 595 if (svc->sc_etype != SVCCFG_SERVICE_OBJECT) 596 uu_die(gettext("bad entity attach: %s is not a service\n"), 597 svc->sc_name); 598 599 if (uu_list_find(svc->sc_u.sc_service.sc_service_instances, ent, NULL, 600 NULL) != NULL) { 601 semerr(gettext("Multiple definitions of entity %s in service " 602 "%s.\n"), ent->sc_name, svc->sc_name); 603 return (-1); 604 } 605 606 (void) uu_list_prepend(svc->sc_u.sc_service.sc_service_instances, ent); 607 ent->sc_parent = svc; 608 ent->sc_fmri = uu_msprintf("%s:%s", svc->sc_fmri, ent->sc_name); 609 if (ent->sc_fmri == NULL) 610 uu_die(gettext("couldn't allocate memory")); 611 612 return (0); 613 } 614 615 int 616 internal_attach_pgroup(entity_t *ent, pgroup_t *pgrp) 617 { 618 if (uu_list_find(ent->sc_pgroups, pgrp, NULL, NULL) != NULL) { 619 semerr(gettext("Multiple definitions of property group %s in " 620 "entity %s.\n"), pgrp->sc_pgroup_name, ent->sc_name); 621 return (-1); 622 } 623 624 (void) uu_list_append(ent->sc_pgroups, pgrp); 625 626 pgrp->sc_parent = ent; 627 628 return (0); 629 } 630 631 int 632 internal_attach_dependent(entity_t *ent, pgroup_t *pg) 633 { 634 if (uu_list_find(ent->sc_dependents, pg, NULL, NULL) != NULL) { 635 semerr(gettext("Multiple definitions of dependent %s in " 636 "entity %s.\n"), pg->sc_pgroup_name, ent->sc_name); 637 return (-1); 638 } 639 640 (void) uu_list_append(ent->sc_dependents, pg); 641 642 pg->sc_parent = ent; 643 644 return (0); 645 } 646 647 /* 648 * Returns 649 * 0 - success 650 * -1 - prop already exists in pgrp 651 */ 652 int 653 internal_attach_property(pgroup_t *pgrp, property_t *prop) 654 { 655 uu_list_index_t idx; 656 657 if (uu_list_find(pgrp->sc_pgroup_props, prop, NULL, &idx) != NULL) { 658 semerr(gettext("Multiple definitions for property %s in " 659 "property group %s.\n"), prop->sc_property_name, 660 pgrp->sc_pgroup_name); 661 return (-1); 662 } 663 664 uu_list_insert(pgrp->sc_pgroup_props, prop, idx); 665 666 return (0); 667 } 668 669 void 670 internal_attach_value(property_t *prop, value_t *val) 671 { 672 uu_list_index_t idx; 673 674 (void) uu_list_find(prop->sc_property_values, val, NULL, &idx); 675 uu_list_insert(prop->sc_property_values, val, idx); 676 } 677 678 /* 679 * These functions create an internal representation of a property group 680 * (pgroup_t) from the repository (scf_propertygroup_t). They are used by the 681 * import functions in svccfg_libscf.c . 682 * 683 * load_init() must be called first to initialize these globals, and 684 * load_fini() should be called afterwards to destroy them. 685 */ 686 687 static char *loadbuf = NULL; 688 static size_t loadbuf_sz; 689 static scf_property_t *load_prop = NULL; 690 static scf_value_t *load_val = NULL; 691 static scf_iter_t *load_propiter = NULL, *load_valiter = NULL; 692 693 /* 694 * Initialize the global state for the load_*() routines. 695 * Returns 696 * 0 - success 697 * ENOMEM - out of memory 698 */ 699 int 700 load_init(void) 701 { 702 loadbuf_sz = ((max_scf_value_len > max_scf_pg_type_len) ? 703 max_scf_value_len : max_scf_pg_type_len) + 1; 704 705 loadbuf = malloc(loadbuf_sz); 706 if (loadbuf == NULL) 707 return (ENOMEM); 708 709 if ((load_prop = scf_property_create(g_hndl)) == NULL || 710 (load_val = scf_value_create(g_hndl)) == NULL || 711 (load_propiter = scf_iter_create(g_hndl)) == NULL || 712 (load_valiter = scf_iter_create(g_hndl)) == NULL) { 713 load_fini(); 714 return (ENOMEM); 715 } 716 717 return (0); 718 } 719 720 void 721 load_fini(void) 722 { 723 scf_iter_destroy(load_propiter); 724 load_propiter = NULL; 725 scf_iter_destroy(load_valiter); 726 load_valiter = NULL; 727 scf_value_destroy(load_val); 728 load_val = NULL; 729 scf_property_destroy(load_prop); 730 load_prop = NULL; 731 free(loadbuf); 732 loadbuf = NULL; 733 } 734 735 /* 736 * Create a property_t which represents an scf_property_t. Returns 737 * 0 - success 738 * ECANCELED - prop's pg was deleted 739 * ECONNABORTED - repository disconnected 740 * ENOMEM - out of memory 741 * EACCES - permission denied when reading property 742 */ 743 static int 744 load_property(scf_property_t *prop, property_t **ipp) 745 { 746 property_t *iprop; 747 int r; 748 ssize_t ssz; 749 750 /* get name */ 751 if (scf_property_get_name(prop, loadbuf, loadbuf_sz) < 0) { 752 switch (scf_error()) { 753 case SCF_ERROR_DELETED: 754 return (ECANCELED); 755 756 case SCF_ERROR_CONNECTION_BROKEN: 757 return (ECONNABORTED); 758 759 case SCF_ERROR_NOT_BOUND: 760 case SCF_ERROR_NOT_SET: 761 default: 762 bad_error("scf_property_get_name", scf_error()); 763 } 764 } 765 766 iprop = internal_property_new(); 767 iprop->sc_property_name = strdup(loadbuf); 768 if (iprop->sc_property_name == NULL) { 769 internal_property_free(iprop); 770 return (ENOMEM); 771 } 772 773 /* get type */ 774 if (scf_property_type(prop, &iprop->sc_value_type) != 0) { 775 switch (scf_error()) { 776 case SCF_ERROR_DELETED: 777 r = ECANCELED; 778 goto out; 779 780 case SCF_ERROR_CONNECTION_BROKEN: 781 r = ECONNABORTED; 782 goto out; 783 784 case SCF_ERROR_NOT_BOUND: 785 case SCF_ERROR_NOT_SET: 786 default: 787 bad_error("scf_property_type", scf_error()); 788 } 789 } 790 791 /* get values */ 792 if (scf_iter_property_values(load_valiter, prop) != 0) { 793 switch (scf_error()) { 794 case SCF_ERROR_DELETED: 795 r = ECANCELED; 796 goto out; 797 798 case SCF_ERROR_CONNECTION_BROKEN: 799 r = ECONNABORTED; 800 goto out; 801 802 case SCF_ERROR_HANDLE_MISMATCH: 803 case SCF_ERROR_NOT_BOUND: 804 case SCF_ERROR_NOT_SET: 805 default: 806 bad_error("scf_iter_property_values", scf_error()); 807 } 808 } 809 810 for (;;) { 811 value_t *ival; 812 813 r = scf_iter_next_value(load_valiter, load_val); 814 if (r == 0) 815 break; 816 if (r != 1) { 817 switch (scf_error()) { 818 case SCF_ERROR_DELETED: 819 r = ECANCELED; 820 goto out; 821 822 case SCF_ERROR_CONNECTION_BROKEN: 823 r = ECONNABORTED; 824 goto out; 825 826 case SCF_ERROR_PERMISSION_DENIED: 827 r = EACCES; 828 goto out; 829 830 case SCF_ERROR_HANDLE_MISMATCH: 831 case SCF_ERROR_NOT_BOUND: 832 case SCF_ERROR_NOT_SET: 833 case SCF_ERROR_INVALID_ARGUMENT: 834 default: 835 bad_error("scf_iter_next_value", scf_error()); 836 } 837 } 838 839 ival = internal_value_new(); 840 ival->sc_type = scf_value_type(load_val); 841 assert(ival->sc_type != SCF_TYPE_INVALID); 842 843 switch (ival->sc_type) { 844 case SCF_TYPE_BOOLEAN: { 845 uint8_t b; 846 847 r = scf_value_get_boolean(load_val, &b); 848 if (r != 0) 849 bad_error("scf_value_get_boolean", scf_error()); 850 ival->sc_u.sc_count = b; 851 break; 852 } 853 854 case SCF_TYPE_COUNT: 855 r = scf_value_get_count(load_val, &ival->sc_u.sc_count); 856 if (r != 0) 857 bad_error("scf_value_get_count", scf_error()); 858 break; 859 860 case SCF_TYPE_INTEGER: 861 r = scf_value_get_integer(load_val, 862 &ival->sc_u.sc_integer); 863 if (r != 0) 864 bad_error("scf_value_get_integer", scf_error()); 865 break; 866 867 default: 868 ssz = scf_value_get_as_string(load_val, loadbuf, 869 loadbuf_sz); 870 if (ssz < 0) 871 bad_error("scf_value_get_as_string", 872 scf_error()); 873 874 ival->sc_u.sc_string = strdup(loadbuf); 875 if (ival->sc_u.sc_string == NULL) { 876 r = ENOMEM; 877 goto out; 878 } 879 880 ival->sc_free = internal_value_free_str; 881 } 882 883 internal_attach_value(iprop, ival); 884 } 885 886 *ipp = iprop; 887 return (0); 888 889 out: 890 free(iprop->sc_property_name); 891 internal_property_free(iprop); 892 return (r); 893 } 894 895 /* 896 * Returns 897 * 0 - success 898 * ECANCELED - pg was deleted 899 * ECONNABORTED - repository disconnected 900 * ENOMEM - out of memory 901 */ 902 int 903 load_pg_attrs(const scf_propertygroup_t *pg, pgroup_t **ipgp) 904 { 905 pgroup_t *ipg; 906 907 ipg = internal_pgroup_new(); 908 909 if (scf_pg_get_flags(pg, &ipg->sc_pgroup_flags) != 0) { 910 switch (scf_error()) { 911 case SCF_ERROR_DELETED: 912 internal_pgroup_free(ipg); 913 return (ECANCELED); 914 915 case SCF_ERROR_CONNECTION_BROKEN: 916 internal_pgroup_free(ipg); 917 return (ECONNABORTED); 918 919 case SCF_ERROR_NOT_SET: 920 case SCF_ERROR_NOT_BOUND: 921 default: 922 bad_error("scf_pg_get_name", scf_error()); 923 } 924 } 925 926 if (scf_pg_get_name(pg, loadbuf, loadbuf_sz) < 0) { 927 switch (scf_error()) { 928 case SCF_ERROR_DELETED: 929 internal_pgroup_free(ipg); 930 return (ECANCELED); 931 932 case SCF_ERROR_CONNECTION_BROKEN: 933 internal_pgroup_free(ipg); 934 return (ECONNABORTED); 935 936 case SCF_ERROR_NOT_SET: 937 case SCF_ERROR_NOT_BOUND: 938 default: 939 bad_error("scf_pg_get_name", scf_error()); 940 } 941 } 942 943 ipg->sc_pgroup_name = strdup(loadbuf); 944 if (ipg->sc_pgroup_name == NULL) { 945 internal_pgroup_free(ipg); 946 return (ENOMEM); 947 } 948 949 if (scf_pg_get_type(pg, loadbuf, loadbuf_sz) < 0) { 950 switch (scf_error()) { 951 case SCF_ERROR_DELETED: 952 free((char *)ipg->sc_pgroup_name); 953 internal_pgroup_free(ipg); 954 return (ECANCELED); 955 956 case SCF_ERROR_CONNECTION_BROKEN: 957 free((char *)ipg->sc_pgroup_name); 958 internal_pgroup_free(ipg); 959 return (ECONNABORTED); 960 961 case SCF_ERROR_NOT_SET: 962 case SCF_ERROR_NOT_BOUND: 963 default: 964 bad_error("scf_pg_get_name", scf_error()); 965 } 966 } 967 968 ipg->sc_pgroup_type = strdup(loadbuf); 969 if (ipg->sc_pgroup_type == NULL) { 970 free((char *)ipg->sc_pgroup_name); 971 internal_pgroup_free(ipg); 972 return (ENOMEM); 973 } 974 975 *ipgp = ipg; 976 return (0); 977 } 978 979 /* 980 * Load a property group into a pgroup_t. Returns 981 * 0 - success 982 * ECANCELED - pg was deleted 983 * ECONNABORTED - repository disconnected 984 * EBADF - pg is corrupt (error printed if fmri is given) 985 * ENOMEM - out of memory 986 * EACCES - permission denied when reading property 987 */ 988 int 989 load_pg(const scf_propertygroup_t *pg, pgroup_t **ipgp, const char *fmri, 990 const char *snapname) 991 { 992 pgroup_t *ipg; 993 int r; 994 995 if (scf_iter_pg_properties(load_propiter, pg) != 0) { 996 switch (scf_error()) { 997 case SCF_ERROR_DELETED: 998 return (ECANCELED); 999 1000 case SCF_ERROR_CONNECTION_BROKEN: 1001 return (ECONNABORTED); 1002 1003 case SCF_ERROR_HANDLE_MISMATCH: 1004 case SCF_ERROR_NOT_SET: 1005 case SCF_ERROR_NOT_BOUND: 1006 default: 1007 bad_error("scf_iter_pg_properties", scf_error()); 1008 } 1009 } 1010 1011 r = load_pg_attrs(pg, &ipg); 1012 switch (r) { 1013 case 0: 1014 break; 1015 1016 case ECANCELED: 1017 case ECONNABORTED: 1018 case ENOMEM: 1019 return (r); 1020 1021 default: 1022 bad_error("load_pg_attrs", r); 1023 } 1024 1025 for (;;) { 1026 property_t *iprop; 1027 1028 r = scf_iter_next_property(load_propiter, load_prop); 1029 if (r == 0) 1030 break; 1031 if (r != 1) { 1032 switch (scf_error()) { 1033 case SCF_ERROR_DELETED: 1034 r = ECANCELED; 1035 goto out; 1036 1037 case SCF_ERROR_CONNECTION_BROKEN: 1038 r = ECONNABORTED; 1039 goto out; 1040 1041 case SCF_ERROR_HANDLE_MISMATCH: 1042 case SCF_ERROR_NOT_BOUND: 1043 case SCF_ERROR_NOT_SET: 1044 case SCF_ERROR_INVALID_ARGUMENT: 1045 default: 1046 bad_error("scf_iter_next_property", 1047 scf_error()); 1048 } 1049 } 1050 1051 r = load_property(load_prop, &iprop); 1052 switch (r) { 1053 case 0: 1054 break; 1055 1056 case ECANCELED: 1057 case ECONNABORTED: 1058 case ENOMEM: 1059 case EACCES: 1060 goto out; 1061 1062 default: 1063 bad_error("load_property", r); 1064 } 1065 1066 r = internal_attach_property(ipg, iprop); 1067 if (r != 0) { 1068 if (fmri != NULL) { 1069 if (snapname == NULL) 1070 warn(gettext("Property group \"%s\" of " 1071 "%s has multiple definitions of " 1072 "property \"%s\".\n"), 1073 ipg->sc_pgroup_name, fmri, 1074 iprop->sc_property_name); 1075 else 1076 warn(gettext("Property group \"%s\" of " 1077 "the \"%s\" snapshot of %s has " 1078 "multiple definitions of property " 1079 "\"%s\".\n"), 1080 ipg->sc_pgroup_name, snapname, fmri, 1081 iprop->sc_property_name); 1082 } 1083 r = EBADF; 1084 goto out; 1085 } 1086 } 1087 1088 *ipgp = ipg; 1089 return (0); 1090 1091 out: 1092 internal_pgroup_free(ipg); 1093 return (r); 1094 } 1095 1096 /* 1097 * These functions compare internal property groups and properties (pgroup_t 1098 * & property_t). They return 1 if the given structures are equal and 1099 * 0 otherwise. Some will report the differences between the two structures. 1100 * They are used by the import functions in svccfg_libscf.c . 1101 */ 1102 1103 int 1104 prop_equal(property_t *p1, property_t *p2, const char *fmri, const char *pgname, 1105 int new) 1106 { 1107 value_t *v1, *v2; 1108 1109 const char * const values_diff = gettext("Conflict upgrading %s " 1110 "(property \"%s/%s\" has different values).\n"); 1111 const char * const values_diff_new = gettext("Conflict upgrading %s " 1112 "(new property \"%s/%s\" has different values).\n"); 1113 1114 assert((fmri == NULL) == (pgname == NULL)); 1115 1116 if (fmri != NULL) { 1117 /* 1118 * If we find any differences, we'll report conflicts. But 1119 * conflict messages won't make any sense if the names don't 1120 * match. If the caller supplied fmri, assert that the names 1121 * match. 1122 */ 1123 assert(strcmp(p1->sc_property_name, p2->sc_property_name) == 0); 1124 } else { 1125 if (strcmp(p1->sc_property_name, p2->sc_property_name) != 0) 1126 return (0); 1127 } 1128 1129 if (p1->sc_value_type != p2->sc_value_type) { 1130 if (fmri != NULL) { 1131 if (new) 1132 warn(gettext("Conflict upgrading %s " 1133 "(new property \"%s/%s\" has different " 1134 "type).\n"), fmri, pgname, 1135 p1->sc_property_name); 1136 else 1137 warn(gettext("Conflict upgrading %s " 1138 "(property \"%s/%s\" has different " 1139 "type).\n"), fmri, pgname, 1140 p1->sc_property_name); 1141 } 1142 return (0); 1143 } 1144 1145 if (uu_list_numnodes(p1->sc_property_values) != 1146 uu_list_numnodes(p2->sc_property_values)) { 1147 if (fmri != NULL) 1148 warn(new ? values_diff_new : values_diff, fmri, 1149 pgname, p1->sc_property_name); 1150 return (0); 1151 } 1152 1153 v1 = uu_list_first(p1->sc_property_values); 1154 v2 = uu_list_first(p2->sc_property_values); 1155 1156 while (v1 != NULL) { 1157 assert(v2 != NULL); 1158 1159 if (value_cmp(v1, v2, NULL) != 0) { 1160 if (fmri != NULL) 1161 warn(new ? values_diff_new : values_diff, 1162 fmri, pgname, p1->sc_property_name); 1163 return (0); 1164 } 1165 1166 v1 = uu_list_next(p1->sc_property_values, v1); 1167 v2 = uu_list_next(p2->sc_property_values, v2); 1168 } 1169 1170 return (1); 1171 } 1172 1173 int 1174 pg_attrs_equal(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri, 1175 int new) 1176 { 1177 if (strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) != 0) { 1178 assert(fmri == NULL); 1179 return (0); 1180 } 1181 1182 if (pg1->sc_pgroup_flags != pg2->sc_pgroup_flags) { 1183 if (fmri) { 1184 if (new) 1185 warn(gettext("Conflict upgrading %s " 1186 "(new property group \"%s\" has different " 1187 "flags).\n"), fmri, pg1->sc_pgroup_name); 1188 else 1189 warn(gettext("Conflict upgrading %s " 1190 "(property group \"%s\" has different " 1191 "flags).\n"), fmri, pg1->sc_pgroup_name); 1192 } 1193 return (0); 1194 } 1195 1196 if (strcmp(pg1->sc_pgroup_type, pg2->sc_pgroup_type) != 0) { 1197 if (fmri) { 1198 if (new) 1199 warn(gettext("Conflict upgrading %s " 1200 "(new property group \"%s\" has different " 1201 "type).\n"), fmri, pg1->sc_pgroup_name); 1202 else 1203 warn(gettext("Conflict upgrading %s " 1204 "(property group \"%s\" has different " 1205 "type).\n"), fmri, pg1->sc_pgroup_name); 1206 } 1207 return (0); 1208 } 1209 1210 return (1); 1211 } 1212 1213 int 1214 pg_equal(pgroup_t *pg1, pgroup_t *pg2) 1215 { 1216 property_t *p1, *p2; 1217 1218 if (!pg_attrs_equal(pg1, pg2, NULL, 0)) 1219 return (0); 1220 1221 if (uu_list_numnodes(pg1->sc_pgroup_props) != 1222 uu_list_numnodes(pg2->sc_pgroup_props)) 1223 return (0); 1224 1225 p1 = uu_list_first(pg1->sc_pgroup_props); 1226 p2 = uu_list_first(pg2->sc_pgroup_props); 1227 1228 while (p1 != NULL) { 1229 assert(p2 != NULL); 1230 1231 if (!prop_equal(p1, p2, NULL, NULL, 0)) 1232 return (0); 1233 1234 p1 = uu_list_next(pg1->sc_pgroup_props, p1); 1235 p2 = uu_list_next(pg2->sc_pgroup_props, p2); 1236 } 1237 1238 return (1); 1239 } 1240