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 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 /* 26 * scf_tmpl.c 27 * 28 * This file implements the bulk of the libscf templates interfaces. 29 * Templates describe metadata about a service or instance in general, 30 * and individual configuration properties on those services and instances. 31 * Human-consumable descriptions can be provided, along with definitions 32 * of valid configuration. See service_bundle.dtd.1 for XML definitions 33 * of templates, and the svccfg code for information on how those definitions 34 * are translated into the repository. 35 * 36 * The main data structures are scf_pg_tmpl and scf_prop_tmpl. These 37 * are allocated by the callers through scf_tmpl_[pg|prop]_create(), and 38 * destroyed with scf_tmpl_[pg|prop]_destroy(). They are populated by 39 * scf_tmpl_get_by_pg_name(), scf_tmpl_get_by_pg(), and 40 * scf_tmpl_get_by_prop(). They also store the iterator state for 41 * scf_tmpl_iter_pgs() and scf_tmpl_iter_props(). 42 * 43 * These data structures are then consumed by other functions to 44 * gather information about the template (e.g. name, description, 45 * choices, constraints, etc.). 46 * 47 * scf_tmpl_validate_fmri() does instance validation against template 48 * data, and populates a set of template errors which can be explored using 49 * the scf_tmpl_next_error() and the scf_tmpl_error*() suite of functions. 50 * 51 * The main data structures for template errors are scf_tmpl_errors, 52 * defined in this file, and scf_tmpl_error, defined in libscf_priv.h. 53 * scf_tmpl_error is shared with svccfg to offer common printing 54 * of error messages between libscf and svccfg. 55 * 56 * General convenience functions are towards the top of this file, 57 * followed by pg and prop template discovery functions, followed 58 * by functions which gather information about the discovered 59 * template. Validation and error functions are at the end of this file. 60 */ 61 62 #include "lowlevel_impl.h" 63 #include "libscf_impl.h" 64 #include <assert.h> 65 #include <errno.h> 66 #include <libintl.h> 67 #include <stdlib.h> 68 #include <stdio.h> 69 #include <strings.h> 70 #include <locale.h> 71 #include <ctype.h> 72 #include <inttypes.h> 73 74 #define SCF_TMPL_PG_COMMON_NAME_C "common_name_C" 75 76 #define SCF__TMPL_ITER_NONE 0 77 #define SCF__TMPL_ITER_INST 1 78 #define SCF__TMPL_ITER_RESTARTER 2 79 #define SCF__TMPL_ITER_GLOBAL 3 80 81 #define SCF_TMPL_PG_NT 0 82 #define SCF_TMPL_PG_N 1 83 #define SCF_TMPL_PG_T 2 84 #define SCF_TMPL_PG_WILD 3 85 86 struct scf_pg_tmpl { 87 int pt_populated; 88 scf_handle_t *pt_h; 89 scf_propertygroup_t *pt_pg; 90 scf_service_t *pt_orig_svc; 91 scf_service_t *pt_svc; 92 scf_instance_t *pt_orig_inst; 93 scf_instance_t *pt_inst; 94 scf_snapshot_t *pt_snap; 95 int pt_is_iter; 96 scf_iter_t *pt_iter; 97 int pt_iter_last; 98 }; 99 100 #define SCF_WALK_ERROR -1 101 #define SCF_WALK_NEXT 0 102 #define SCF_WALK_DONE 1 103 104 struct pg_tmpl_walk { 105 const char *pw_snapname; 106 const char *pw_pgname; 107 const char *pw_pgtype; 108 scf_instance_t *pw_inst; 109 scf_service_t *pw_svc; 110 scf_snapshot_t *pw_snap; 111 scf_propertygroup_t *pw_pg; 112 const char *pw_target; 113 char *pw_tmpl_pgname; 114 }; 115 116 typedef struct pg_tmpl_walk pg_tmpl_walk_t; 117 118 typedef int walk_template_inst_func_t(scf_service_t *_svc, 119 scf_instance_t *_inst, pg_tmpl_walk_t *p); 120 121 struct scf_prop_tmpl { 122 int prt_populated; 123 scf_handle_t *prt_h; 124 scf_pg_tmpl_t *prt_t; 125 scf_propertygroup_t *prt_pg; 126 char *prt_pg_name; 127 scf_iter_t *prt_iter; 128 }; 129 130 /* 131 * Common server errors are usually passed back to the caller. This 132 * array defines them centrally so that they don't need to be enumerated 133 * in every libscf call. 134 */ 135 static const scf_error_t errors_server[] = { 136 SCF_ERROR_BACKEND_ACCESS, 137 SCF_ERROR_CONNECTION_BROKEN, 138 SCF_ERROR_DELETED, 139 SCF_ERROR_HANDLE_DESTROYED, 140 SCF_ERROR_INTERNAL, 141 SCF_ERROR_NO_MEMORY, 142 SCF_ERROR_NO_RESOURCES, 143 SCF_ERROR_NOT_BOUND, 144 SCF_ERROR_PERMISSION_DENIED, 145 0 146 }; 147 148 /* 149 * int ismember() 150 * 151 * Returns 1 if the supplied error is a member of the error array, 0 152 * if it is not. 153 */ 154 int 155 ismember(const scf_error_t error, const scf_error_t error_array[]) 156 { 157 int i; 158 159 for (i = 0; error_array[i] != 0; ++i) { 160 if (error == error_array[i]) 161 return (1); 162 } 163 164 return (0); 165 } 166 167 /* 168 * char *_scf_tmpl_get_fmri() 169 * 170 * Given a pg_tmpl, returns the FMRI of the service or instance that 171 * template describes. The allocated string must be freed with free(). 172 * 173 * On failure, returns NULL and sets scf_error() to _CONNECTION_BROKEN, 174 * _DELETED, or _NO_MEMORY. 175 */ 176 static char * 177 _scf_tmpl_get_fmri(const scf_pg_tmpl_t *t) 178 { 179 ssize_t sz = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH) + 1; 180 int r; 181 char *buf = malloc(sz); 182 183 assert(t->pt_svc != NULL || t->pt_inst != NULL); 184 assert(t->pt_svc == NULL || t->pt_inst == NULL); 185 186 if (buf == NULL) { 187 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 188 return (buf); 189 } 190 191 if (t->pt_inst != NULL) 192 r = scf_instance_to_fmri(t->pt_inst, buf, sz); 193 else 194 r = scf_service_to_fmri(t->pt_svc, buf, sz); 195 196 if (r == -1) { 197 if (ismember(scf_error(), errors_server)) { 198 free(buf); 199 buf = NULL; 200 } else { 201 assert(0); 202 abort(); 203 } 204 } 205 206 return (buf); 207 } 208 209 /* 210 * char *_scf_get_pg_type() 211 * 212 * Given a propertygroup, returns an allocated string containing the 213 * type. The string must be freed with free(). 214 * 215 * On failure, returns NULL and sets scf_error() to: _CONNECTION_BROKEN, 216 * _DELETED, or _NO_MEMORY. 217 */ 218 static char * 219 _scf_get_pg_type(scf_propertygroup_t *pg) 220 { 221 ssize_t sz = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH) + 1; 222 char *buf = malloc(sz); 223 224 if (buf == NULL) { 225 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 226 } else if (scf_pg_get_type(pg, buf, sz) == -1) { 227 if (ismember(scf_error(), errors_server)) { 228 free(buf); 229 buf = NULL; 230 } else { 231 assert(0); 232 abort(); 233 } 234 } 235 236 return (buf); 237 } 238 239 /* 240 * char *_scf_get_prop_name() 241 * 242 * Given a property, returns the name in an allocated string. The string must 243 * be freed with free(). 244 * 245 * On error, returns NULL and sets scf_error() to _CONNECTION_BROKEN, 246 * _DELETED, or _NO_MEMORY. 247 */ 248 static char * 249 _scf_get_prop_name(scf_property_t *prop) 250 { 251 ssize_t sz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1; 252 char *buf = malloc(sz); 253 254 if (buf == NULL) { 255 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 256 } else if (scf_property_get_name(prop, buf, sz) == -1) { 257 if (ismember(scf_error(), errors_server)) { 258 free(buf); 259 buf = NULL; 260 } else { 261 assert(0); 262 abort(); 263 } 264 } 265 266 return (buf); 267 } 268 269 /* 270 * char *_scf_get_prop_type() 271 * 272 * Given a property, returns the type in an allocated string. The string must 273 * be freed with free(). 274 * 275 * On error, returns NULL and sets scf_error() to _CONNECTION_BROKEN, 276 * _DELETED, or _NO_MEMORY. 277 */ 278 static char * 279 _scf_get_prop_type(scf_property_t *prop) 280 { 281 scf_type_t type; 282 char *ret; 283 284 if (scf_property_type(prop, &type) == -1) { 285 if (ismember(scf_error(), errors_server)) { 286 return (NULL); 287 } else { 288 assert(0); 289 abort(); 290 } 291 } 292 293 ret = strdup(scf_type_to_string(type)); 294 if (ret == NULL) 295 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 296 297 return (ret); 298 } 299 300 /* 301 * int _read_single_value_from_pg() 302 * 303 * Reads a single value from the pg and property name specified. On success, 304 * returns an allocated value that must be freed. 305 * 306 * Returns -1 on failure, sets scf_error() to: 307 * SCF_ERROR_BACKEND_ACCESS 308 * SCF_ERROR_CONNECTION_BROKEN 309 * SCF_ERROR_CONSTRAINT_VIOLATED 310 * Property has more than one value associated with it. 311 * SCF_ERROR_DELETED 312 * SCF_ERROR_HANDLE_DESTROYED 313 * SCF_ERROR_INTERNAL 314 * SCF_ERROR_INVALID_ARGUMENT 315 * prop_name not a valid property name. 316 * SCF_ERROR_NO_MEMORY 317 * SCF_ERROR_NO_RESOURCES 318 * SCF_ERROR_NOT_BOUND 319 * SCF_ERROR_NOT_FOUND 320 * Property doesn't exist or exists and has no value. 321 * SCF_ERROR_NOT_SET 322 * Property group specified by pg is not set. 323 * SCF_ERROR_PERMISSION_DENIED 324 */ 325 static int 326 _read_single_value_from_pg(scf_propertygroup_t *pg, const char *prop_name, 327 scf_value_t **val) 328 { 329 scf_handle_t *h; 330 scf_property_t *prop; 331 int ret = 0; 332 333 assert(val != NULL); 334 if ((h = scf_pg_handle(pg)) == NULL) { 335 assert(scf_error() == SCF_ERROR_HANDLE_DESTROYED); 336 return (-1); 337 } 338 339 prop = scf_property_create(h); 340 *val = scf_value_create(h); 341 342 if (prop == NULL || *val == NULL) { 343 assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT); 344 goto read_single_value_from_pg_fail; 345 } 346 347 if (scf_pg_get_property(pg, prop_name, prop) != 0) { 348 assert(scf_error() != SCF_ERROR_HANDLE_MISMATCH); 349 goto read_single_value_from_pg_fail; 350 } 351 352 if (scf_property_get_value(prop, *val) == -1) { 353 assert(scf_error() != SCF_ERROR_NOT_SET); 354 assert(scf_error() != SCF_ERROR_HANDLE_MISMATCH); 355 goto read_single_value_from_pg_fail; 356 } 357 358 goto read_single_value_from_pg_done; 359 360 read_single_value_from_pg_fail: 361 scf_value_destroy(*val); 362 *val = NULL; 363 ret = -1; 364 365 read_single_value_from_pg_done: 366 scf_property_destroy(prop); 367 return (ret); 368 } 369 370 /* 371 * char *_scf_read_single_astring_from_pg() 372 * 373 * Reads an astring from the pg and property name specified. On success, 374 * returns an allocated string. The string must be freed with free(). 375 * 376 * Returns NULL on failure, sets scf_error() to: 377 * SCF_ERROR_BACKEND_ACCESS 378 * SCF_ERROR_CONNECTION_BROKEN 379 * SCF_ERROR_CONSTRAINT_VIOLATED 380 * Property has more than one value associated with it. 381 * SCF_ERROR_DELETED 382 * SCF_ERROR_HANDLE_DESTROYED 383 * SCF_ERROR_INTERNAL 384 * SCF_ERROR_INVALID_ARGUMENT 385 * prop_name not a valid property name. 386 * SCF_ERROR_NO_MEMORY 387 * SCF_ERROR_NO_RESOURCES 388 * SCF_ERROR_NOT_BOUND 389 * SCF_ERROR_NOT_FOUND 390 * Property doesn't exist or exists and has no value. 391 * SCF_ERROR_NOT_SET 392 * The property group specified by pg is not set. 393 * SCF_ERROR_PERMISSION_DENIED 394 * SCF_ERROR_TYPE_MISMATCH 395 */ 396 char * 397 _scf_read_single_astring_from_pg(scf_propertygroup_t *pg, const char *prop_name) 398 { 399 scf_value_t *val; 400 char *ret = NULL; 401 ssize_t rsize = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH) + 1; 402 403 assert(rsize != 0); 404 if (_read_single_value_from_pg(pg, prop_name, &val) == -1) 405 return (NULL); 406 407 ret = malloc(rsize); 408 if (ret == NULL) { 409 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 410 goto cleanup; 411 } 412 413 if (scf_value_get_astring(val, ret, rsize) < 0) { 414 assert(scf_error() != SCF_ERROR_NOT_SET); 415 free(ret); 416 ret = NULL; 417 } 418 419 cleanup: 420 scf_value_destroy(val); 421 return (ret); 422 } 423 424 /* 425 * char *_scf_read_tmpl_prop_type_as_string() 426 * 427 * Reads the property type and returns it as an allocated string. The string 428 * must be freed with free(). 429 * 430 * Returns NULL on failure, sets scf_error() to _BACKEND_ACCESS, 431 * _CONNECTION_BROKEN, _DELETED, _HANDLE_DESTROYED, _INTERNAL, _NO_MEMORY, 432 * _NO_RESOURCES, _NOT_BOUND, _PERMISSION_DENIED, or _TEMPLATE_INVALID. 433 */ 434 char * 435 _scf_read_tmpl_prop_type_as_string(const scf_prop_tmpl_t *pt) 436 { 437 char *type; 438 439 type = _scf_read_single_astring_from_pg(pt->prt_pg, 440 SCF_PROPERTY_TM_TYPE); 441 if (type == NULL) { 442 if (ismember(scf_error(), errors_server)) { 443 return (NULL); 444 } else switch (scf_error()) { 445 case SCF_ERROR_CONSTRAINT_VIOLATED: 446 case SCF_ERROR_NOT_FOUND: 447 case SCF_ERROR_TYPE_MISMATCH: 448 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID); 449 return (NULL); 450 451 case SCF_ERROR_INVALID_ARGUMENT: 452 case SCF_ERROR_NOT_SET: 453 default: 454 assert(0); 455 abort(); 456 } 457 } 458 459 return (type); 460 } 461 462 /* 463 * int _read_single_boolean_from_pg() 464 * 465 * Reads a boolean from the pg and property name specified. 466 * 467 * Returns -1 on failure, sets scf_error() to: 468 * SCF_ERROR_BACKEND_ACCESS 469 * SCF_ERROR_CONNECTION_BROKEN 470 * SCF_ERROR_CONSTRAINT_VIOLATED 471 * Property has more than one value associated with it. 472 * SCF_ERROR_DELETED 473 * SCF_ERROR_HANDLE_DESTROYED 474 * SCF_ERROR_INTERNAL 475 * SCF_ERROR_INVALID_ARGUMENT 476 * prop_name is not a valid property name. 477 * SCF_ERROR_NO_MEMORY 478 * SCF_ERROR_NO_RESOURCES 479 * SCF_ERROR_NOT_BOUND 480 * SCF_ERROR_NOT_FOUND 481 * Property doesn't exist or exists and has no value. 482 * SCF_ERROR_NOT_SET 483 * The property group specified by pg is not set. 484 * SCF_ERROR_PERMISSION_DENIED 485 * SCF_ERROR_TYPE_MISMATCH 486 */ 487 static int 488 _read_single_boolean_from_pg(scf_propertygroup_t *pg, const char *prop_name, 489 uint8_t *bool) 490 { 491 scf_value_t *val; 492 int ret = 0; 493 494 if (_read_single_value_from_pg(pg, prop_name, &val) == -1) 495 return (-1); 496 497 if (scf_value_get_boolean(val, bool) < 0) { 498 assert(scf_error() != SCF_ERROR_NOT_SET); 499 ret = -1; 500 } 501 502 scf_value_destroy(val); 503 return (ret); 504 } 505 506 /* 507 * static char ** _append_astrings_values() 508 * 509 * This function reads the values from the property prop_name in pg and 510 * appends to an existing scf_values_t *vals. vals may be empty, but 511 * must exist. The function skips over zero-length and duplicate values. 512 * 513 * Returns NULL on failure, sets scf_error() to: 514 * SCF_ERROR_BACKEND_ACCESS 515 * SCF_ERROR_CONNECTION_BROKEN 516 * SCF_ERROR_DELETED 517 * SCF_ERROR_HANDLE_DESTROYED 518 * SCF_ERROR_INTERNAL 519 * SCF_ERROR_INVALID_ARGUMENT 520 * prop_name is not a valid property name. 521 * SCF_ERROR_NO_MEMORY 522 * SCF_ERROR_NO_RESOURCES 523 * SCF_ERROR_NOT_BOUND 524 * SCF_ERROR_NOT_FOUND 525 * SCF_ERROR_NOT_SET 526 * SCF_ERROR_PERMISSION_DENIED 527 * SCF_ERROR_TYPE_MISMATCH 528 */ 529 static char ** 530 _append_astrings_values(scf_propertygroup_t *pg, const char *prop_name, 531 scf_values_t *vals) 532 { 533 scf_handle_t *h; 534 scf_property_t *prop; 535 scf_value_t *val; 536 scf_iter_t *iter; 537 ssize_t rsize = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH) + 1; 538 int err, count, cursz, i; 539 540 assert(vals != NULL); 541 assert(vals->value_type == SCF_TYPE_ASTRING); 542 assert(vals->reserved == NULL); 543 count = vals->value_count; 544 if (count == 0) { 545 cursz = 8; 546 vals->values.v_astring = calloc(cursz, sizeof (char *)); 547 if (vals->values.v_astring == NULL) { 548 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 549 return (NULL); 550 } 551 } else { 552 /* 553 * The array may be bigger, but it is irrelevant since 554 * we will always re-allocate a new one. 555 */ 556 cursz = count; 557 } 558 559 if ((h = scf_pg_handle(pg)) == NULL) { 560 assert(scf_error() == SCF_ERROR_HANDLE_DESTROYED); 561 return (NULL); 562 } 563 564 prop = scf_property_create(h); 565 val = scf_value_create(h); 566 iter = scf_iter_create(h); 567 568 if (prop == NULL || val == NULL || iter == NULL) { 569 assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT); 570 goto append_single_astring_from_pg_fail; 571 } 572 573 if (scf_pg_get_property(pg, prop_name, prop) != 0) { 574 assert(scf_error() != SCF_ERROR_HANDLE_MISMATCH); 575 goto append_single_astring_from_pg_fail; 576 } 577 578 if (scf_iter_property_values(iter, prop) != 0) { 579 assert(scf_error() != SCF_ERROR_NOT_SET); 580 assert(scf_error() != SCF_ERROR_HANDLE_MISMATCH); 581 goto append_single_astring_from_pg_fail; 582 } 583 584 while ((err = scf_iter_next_value(iter, val)) == 1) { 585 int flag; 586 int r; 587 588 if (count + 1 >= cursz) { 589 void *aux; 590 591 cursz *= 2; 592 if ((aux = calloc(cursz, sizeof (char *))) == NULL) { 593 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 594 goto append_single_astring_from_pg_fail; 595 } 596 (void) memcpy(aux, vals->values.v_astring, 597 count * sizeof (char *)); 598 free(vals->values.v_astring); 599 vals->values.v_astring = aux; 600 } 601 602 vals->values.v_astring[count] = malloc(rsize); 603 if (vals->values.v_astring[count] == NULL) { 604 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 605 goto append_single_astring_from_pg_fail; 606 } 607 608 if ((r = scf_value_get_astring(val, 609 vals->values.v_astring[count], rsize)) <= 0) { 610 /* discard zero length strings */ 611 if (r == 0) { 612 free(vals->values.v_astring[count]); 613 continue; 614 } 615 assert(scf_error() != SCF_ERROR_NOT_SET); 616 goto append_single_astring_from_pg_fail; 617 } 618 for (i = 0, flag = 0; i < count; ++i) { 619 /* find and discard duplicates */ 620 if (strncmp(vals->values.v_astring[i], 621 vals->values.v_astring[count], rsize) == 0) { 622 free(vals->values.v_astring[count]); 623 flag = 1; 624 break; 625 } 626 } 627 if (flag == 1) 628 continue; 629 630 count++; 631 } 632 633 vals->value_count = count; 634 635 if (err != 0) { 636 assert(scf_error() != SCF_ERROR_NOT_SET); 637 assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT); 638 assert(scf_error() != SCF_ERROR_HANDLE_MISMATCH); 639 goto append_single_astring_from_pg_fail; 640 } else { 641 vals->values_as_strings = vals->values.v_astring; 642 } 643 644 goto append_single_astring_from_pg_done; 645 646 append_single_astring_from_pg_fail: 647 for (i = 0; i <= count; ++i) { 648 if (vals->values.v_astring[i] != NULL) 649 free(vals->values.v_astring[i]); 650 vals->values.v_astring[i] = NULL; 651 } 652 free(vals->values.v_astring); 653 vals->values.v_astring = NULL; 654 vals->value_count = 0; 655 656 append_single_astring_from_pg_done: 657 scf_iter_destroy(iter); 658 scf_property_destroy(prop); 659 scf_value_destroy(val); 660 return (vals->values.v_astring); 661 } 662 663 /* 664 * Returns NULL on failure, sets scf_error() to: 665 * SCF_ERROR_BACKEND_ACCESS 666 * SCF_ERROR_CONNECTION_BROKEN 667 * SCF_ERROR_DELETED 668 * SCF_ERROR_HANDLE_DESTROYED 669 * SCF_ERROR_INTERNAL 670 * SCF_ERROR_INVALID_ARGUMENT 671 * prop_name is not a valid property name. 672 * SCF_ERROR_NO_MEMORY 673 * SCF_ERROR_NO_RESOURCES 674 * SCF_ERROR_NOT_BOUND 675 * SCF_ERROR_NOT_FOUND 676 * SCF_ERROR_NOT_SET 677 * SCF_ERROR_PERMISSION_DENIED 678 * SCF_ERROR_TYPE_MISMATCH 679 */ 680 static char ** 681 _read_astrings_values(scf_propertygroup_t *pg, const char *prop_name, 682 scf_values_t *vals) 683 { 684 assert(vals != NULL); 685 vals->value_count = 0; 686 vals->value_type = SCF_TYPE_ASTRING; 687 vals->reserved = NULL; 688 return (_append_astrings_values(pg, prop_name, vals)); 689 } 690 691 void 692 _scf_sanitize_locale(char *locale) 693 { 694 for (; *locale != '\0'; locale++) 695 if (!isalnum(*locale) && *locale != '_') 696 *locale = '_'; 697 } 698 699 /* 700 * The returned string needs to be freed by the caller 701 * Returns NULL on failure. Sets scf_error() to: 702 * SCF_ERROR_NO_MEMORY 703 * SCF_ERROR_INVALID_ARGUMENT 704 * Name isn't short enough to add the locale to. 705 */ 706 static char * 707 _add_locale_to_name(const char *name, const char *locale) 708 { 709 char *lname = NULL; 710 ssize_t lsz; 711 char *loc; 712 713 if (locale == NULL) 714 locale = setlocale(LC_MESSAGES, NULL); 715 loc = strdup(locale); 716 if (loc == NULL) { 717 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 718 return (NULL); 719 } else { 720 _scf_sanitize_locale(loc); 721 } 722 723 lsz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1; 724 lname = malloc(lsz); 725 if (lname == NULL) { 726 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 727 goto cleanup; 728 } 729 730 (void) strlcpy(lname, name, lsz); 731 if (strlcat(lname, loc, lsz) >= lsz) { 732 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 733 free(lname); 734 lname = NULL; 735 } 736 cleanup: 737 free(loc); 738 739 return (lname); 740 } 741 742 /* 743 * char *_tmpl_pg_name(pg, type, use_type) 744 * 745 * pg and type can both be NULL. Returns the name of the most specific 746 * template property group name based on the inputs. 747 * If use_type is set and pg is not NULL, a property group name for a 748 * property group template that has type defined is returned, even if no 749 * type is provided. 750 * 751 * Returns NULL on failure and sets scf_error() to: 752 * SCF_ERROR_INVALID_ARGUMENT 753 * can't combine the arguments and get a reasonable length name 754 * SCF_ERROR_NO_MEMORY 755 * 756 */ 757 static char * 758 _tmpl_pg_name(const char *pg, const char *type, int use_type) 759 { 760 char *name; 761 ssize_t limit, size = 0; 762 763 limit = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1; 764 name = malloc(limit); 765 if (name == NULL) { 766 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 767 return (NULL); 768 } 769 770 if (pg == NULL && type == NULL) { 771 if (strlcpy(name, SCF_PG_TM_PG_PATTERN_PREFIX, limit) >= 772 limit) { 773 assert(0); 774 abort(); 775 } 776 return (name); 777 } else if (pg != NULL && type != NULL) { 778 size = snprintf(name, limit, "%s%s", 779 SCF_PG_TM_PG_PATTERN_NT_PREFIX, pg); 780 } else if (pg != NULL && type == NULL && use_type == 1) { 781 size = snprintf(name, limit, "%s%s", 782 SCF_PG_TM_PG_PATTERN_NT_PREFIX, pg); 783 } else if (pg != NULL && type == NULL) { 784 size = snprintf(name, limit, "%s%s", 785 SCF_PG_TM_PG_PATTERN_N_PREFIX, pg); 786 } else if (type != NULL && pg == NULL) { 787 size = snprintf(name, limit, "%s%s", 788 SCF_PG_TM_PG_PATTERN_T_PREFIX, type); 789 } else { 790 assert(0); 791 abort(); 792 } 793 794 if (size >= limit) { 795 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 796 free(name); 797 return (NULL); 798 } else { 799 return (name); 800 } 801 } 802 803 /* 804 * _scf_get_pg_name() 805 * Gets the name of the supplied property group. On success, returns an 806 * allocated string. The string must be freed by free(). 807 * 808 * Returns NULL on failure and sets scf_error() to _CONNECTION_BROKEN, 809 * _DELETED, or _NO_MEMORY. 810 */ 811 static char * 812 _scf_get_pg_name(scf_propertygroup_t *pg) 813 { 814 ssize_t sz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1; 815 char *buf = malloc(sz); 816 817 if (buf == NULL) { 818 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 819 } else if (scf_pg_get_name(pg, buf, sz) == -1) { 820 if (ismember(scf_error(), errors_server)) { 821 free(buf); 822 buf = NULL; 823 } else { 824 assert(0); 825 abort(); 826 } 827 } 828 829 return (buf); 830 } 831 832 /* 833 * char *_tmpl_prop_name() 834 * 835 * Returns the name of the property template prop (which is the name of 836 * the property template property group) in the property group 837 * template t. Returns NULL on failure and sets scf_error() to: 838 * SCF_ERROR_CONNECTION_BROKEN 839 * SCF_ERROR_DELETED 840 * SCF_ERROR_INVALID_ARGUMENT 841 * can't combine the arguments and get a reasonable length name 842 * SCF_ERROR_NO_MEMORY 843 */ 844 static char * 845 _tmpl_prop_name(const char *prop, scf_pg_tmpl_t *t) 846 { 847 char *name = NULL, *pg_name = NULL; 848 size_t prefix_size; 849 ssize_t limit, size = 0; 850 851 assert(prop != NULL); 852 assert(t->pt_pg != NULL); 853 854 limit = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1; 855 name = malloc(limit); 856 if (name == NULL) { 857 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 858 return (NULL); 859 } 860 861 if ((pg_name = _scf_get_pg_name(t->pt_pg)) == NULL) { 862 free(name); 863 return (NULL); 864 } 865 866 prefix_size = strlen(SCF_PG_TM_PG_PAT_BASE); 867 if (strncmp(pg_name, SCF_PG_TM_PG_PAT_BASE, prefix_size) != 0) { 868 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 869 free(name); 870 free(pg_name); 871 return (NULL); 872 } 873 874 size = snprintf(name, limit, "%s%s_%s", SCF_PG_TM_PROP_PATTERN_PREFIX, 875 pg_name + prefix_size, prop); 876 877 if (size >= limit) { 878 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 879 free(name); 880 free(pg_name); 881 return (NULL); 882 } else { 883 free(pg_name); 884 return (name); 885 } 886 } 887 888 /* 889 * int _get_snapshot() 890 * 891 * Gets the specified snapshot. If "snapshot" isn't defined, use the 892 * running snapshot. If the snapshot isn't found, that may or may 893 * not be an error depending on the caller. Return 0 in that case, 894 * but leave scf_error() set to SCF_ERROR_NOT_FOUND. On all other 895 * errors, set scf_error() to: 896 * SCF_ERROR_BACKEND_ACCESS 897 * SCF_ERROR_CONNECTION_BROKEN 898 * SCF_ERROR_DELETED 899 * SCF_ERR_HANDLE_DESTROYED 900 * SCF_ERROR_INTERNAL 901 * SCF_ERROR_INVALID_ARGUMENT 902 * The handle argument is NULL, or snaphot is not a valid snapshot name 903 * SCF_ERROR_NO_MEMORY 904 * SCF_ERROR_NO_RESOURCES 905 * SCF_ERROR_NOT_BOUND 906 * SCF_ERROR_NOT_FOUND 907 */ 908 static int 909 _get_snapshot(scf_instance_t *inst, const char *snapshot, 910 scf_snapshot_t **snap) 911 { 912 int err; 913 scf_handle_t *h; 914 915 h = scf_instance_handle(inst); 916 if (h == NULL) 917 return (-1); 918 919 if ((*snap = scf_snapshot_create(h)) == NULL) { 920 return (-1); 921 } 922 923 /* Use running snapshot by default. */ 924 if (snapshot == NULL) 925 err = scf_instance_get_snapshot(inst, "running", *snap); 926 else 927 err = scf_instance_get_snapshot(inst, snapshot, *snap); 928 929 if (err != 0) { 930 if (ismember(scf_error(), errors_server)) { 931 scf_snapshot_destroy(*snap); 932 *snap = NULL; 933 return (-1); 934 } else switch (scf_error()) { 935 case SCF_ERROR_INVALID_ARGUMENT: 936 scf_snapshot_destroy(*snap); 937 *snap = NULL; 938 return (-1); 939 940 case SCF_ERROR_NOT_FOUND: 941 scf_snapshot_destroy(*snap); 942 *snap = NULL; 943 return (0); 944 945 case SCF_ERROR_NOT_SET: 946 case SCF_ERROR_HANDLE_MISMATCH: 947 default: 948 assert(0); 949 abort(); 950 } 951 } 952 953 /* 954 * Explicitly set SCF_ERROR_NONE so that the SCF_ERROR_NOT_FOUND 955 * return above is explicitly guaranteed to be from 956 * scf_instance_get_snapshot(). 957 */ 958 (void) scf_set_error(SCF_ERROR_NONE); 959 return (0); 960 } 961 962 /* 963 * Returns NULL on error, sets scf_error() to: 964 * SCF_ERROR_BACKEND_ACCESS 965 * SCF_ERROR_CONNECTION_BROKEN 966 * SCF_ERROR_CONSTRAINT_VIOLATED 967 * The restarter's FMRI does not match an existing instance. 968 * SCF_ERROR_DELETED 969 * SCF_ERROR_HANDLE_DESTROYED 970 * SCF_ERROR_INTERNAL 971 * SCF_ERROR_INVALID_ARGUMENT 972 * The restarter's FMRI is not a valid FMRI. 973 * SCF_ERROR_NO_MEMORY 974 * SCF_ERROR_NO_RESOURCES 975 * SCF_ERROR_NOT_BOUND 976 * SCF_ERROR_NOT_FOUND 977 * Property doesn't exist or exists and has no value. 978 * SCF_ERROR_TEMPLATE_INVALID 979 * restarter property is not SCF_TYPE_ASTRING or has more than one value 980 */ 981 static scf_instance_t * 982 _get_restarter_inst(scf_handle_t *h, scf_service_t *svc, 983 scf_instance_t *inst, scf_snapshot_t *s) 984 { 985 char *restarter = NULL; 986 scf_instance_t *ri = NULL; 987 scf_propertygroup_t *pg = NULL; 988 int ret = 0; 989 990 assert(svc != NULL || inst != NULL); 991 assert(svc == NULL || inst == NULL); 992 993 if ((ri = scf_instance_create(h)) == NULL || 994 (pg = scf_pg_create(h)) == NULL) { 995 assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT); 996 goto _get_restarter_inst_fail; 997 } 998 999 if (inst != NULL) 1000 ret = scf_instance_get_pg_composed(inst, s, SCF_PG_GENERAL, 1001 pg); 1002 else 1003 ret = scf_service_get_pg(svc, SCF_PG_GENERAL, pg); 1004 1005 if (ret != 0) { 1006 if (ismember(scf_error(), errors_server)) { 1007 goto _get_restarter_inst_fail; 1008 } else switch (scf_error()) { 1009 case SCF_ERROR_NOT_FOUND: 1010 /* Assume default restarter. */ 1011 break; 1012 1013 case SCF_ERROR_NOT_SET: 1014 case SCF_ERROR_HANDLE_MISMATCH: 1015 /* 1016 * If the arguments to the above functions 1017 * aren't derived from the same handle, there's 1018 * something wrong with the internal implementation, 1019 * not the public caller further up the chain. 1020 */ 1021 case SCF_ERROR_INVALID_ARGUMENT: 1022 default: 1023 assert(0); 1024 abort(); 1025 } 1026 } else { 1027 restarter = _scf_read_single_astring_from_pg(pg, 1028 SCF_PROPERTY_RESTARTER); 1029 /* zero length string is NOT a valid restarter */ 1030 if (restarter != NULL && restarter[0] == '\0') { 1031 free(restarter); 1032 restarter = NULL; 1033 } else if (restarter == NULL) { 1034 if (ismember(scf_error(), errors_server)) { 1035 goto _get_restarter_inst_fail; 1036 } else switch (scf_error()) { 1037 case SCF_ERROR_NOT_FOUND: 1038 break; 1039 1040 case SCF_ERROR_CONSTRAINT_VIOLATED: 1041 case SCF_ERROR_TYPE_MISMATCH: 1042 (void) scf_set_error( 1043 SCF_ERROR_TEMPLATE_INVALID); 1044 goto _get_restarter_inst_fail; 1045 1046 case SCF_ERROR_NOT_SET: 1047 case SCF_ERROR_INVALID_ARGUMENT: 1048 default: 1049 assert(0); 1050 abort(); 1051 } 1052 } 1053 } 1054 1055 if (restarter == NULL) { 1056 /* Use default restarter */ 1057 restarter = strdup(SCF_SERVICE_STARTD); 1058 if (restarter == NULL) { 1059 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1060 goto _get_restarter_inst_fail; 1061 } 1062 } 1063 1064 if (scf_handle_decode_fmri(h, restarter, NULL, NULL, ri, NULL, NULL, 1065 SCF_DECODE_FMRI_EXACT|SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) { 1066 if (ismember(scf_error(), errors_server)) { 1067 goto _get_restarter_inst_fail; 1068 } else switch (scf_error()) { 1069 case SCF_ERROR_CONSTRAINT_VIOLATED: 1070 case SCF_ERROR_INVALID_ARGUMENT: 1071 case SCF_ERROR_NOT_FOUND: 1072 goto _get_restarter_inst_fail; 1073 1074 case SCF_ERROR_HANDLE_MISMATCH: 1075 case SCF_ERROR_NOT_SET: 1076 default: 1077 assert(0); 1078 abort(); 1079 } 1080 } 1081 free(restarter); 1082 scf_pg_destroy(pg); 1083 1084 return (ri); 1085 1086 _get_restarter_inst_fail: 1087 free(restarter); 1088 scf_instance_destroy(ri); 1089 scf_pg_destroy(pg); 1090 return (NULL); 1091 } 1092 1093 /* 1094 * Returns NULL on error, sets scf_error() to: 1095 * SCF_ERROR_BACKEND_ACCESS 1096 * SCF_ERROR_CONNECTION_BROKEN 1097 * SCF_ERROR_CONSTRAINT_VIOLATED 1098 * Restarter property has more than one value associated with it, 1099 * or FMRI does not meet restrictions in scf_handle_decode_fmri() flags. 1100 * SCF_ERROR_DELETED 1101 * SCF_ERROR_HANDLE_DESTROYED 1102 * SCF_ERROR_INTERNAL 1103 * SCF_ERROR_INVALID_ARGUMENT 1104 * The fmri argument in scf_handle_decode_fmri() is not a valid FMRI. 1105 * SCF_ERROR_NO_MEMORY 1106 * SCF_ERROR_NO_RESOURCES 1107 * SCF_ERROR_NOT_BOUND 1108 * SCF_ERROR_NOT_FOUND 1109 * Property doesn't exist or exists and has no value. 1110 */ 1111 static scf_instance_t * 1112 _get_global_inst(scf_handle_t *h) 1113 { 1114 scf_instance_t *ri; 1115 1116 if ((ri = scf_instance_create(h)) == NULL) { 1117 assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT); 1118 (void) scf_set_error(SCF_ERROR_NO_RESOURCES); 1119 return (NULL); 1120 } 1121 1122 if (scf_handle_decode_fmri(h, SCF_INSTANCE_GLOBAL, NULL, NULL, ri, 1123 NULL, NULL, 1124 SCF_DECODE_FMRI_EXACT|SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) { 1125 if (ismember(scf_error(), errors_server)) { 1126 scf_instance_destroy(ri); 1127 return (NULL); 1128 } else switch (scf_error()) { 1129 case SCF_ERROR_CONSTRAINT_VIOLATED: 1130 case SCF_ERROR_INVALID_ARGUMENT: 1131 case SCF_ERROR_NOT_FOUND: 1132 scf_instance_destroy(ri); 1133 return (NULL); 1134 1135 case SCF_ERROR_HANDLE_MISMATCH: 1136 case SCF_ERROR_NOT_SET: 1137 default: 1138 assert(0); 1139 abort(); 1140 } 1141 } 1142 1143 return (ri); 1144 } 1145 1146 /* 1147 * Call the supplied function for each of the service or instance, the 1148 * service's restarter, and the globally defined template instance. 1149 * If the function returns SCF_WALK_ERROR, the walk is ended. If 1150 * the function returns SCF_WALK_NEXT, the next entity is tried. 1151 * 1152 * The function is only expected to return SCF_WALK_DONE if it has 1153 * found a property group match in the current entity, and has 1154 * populated p->pw_pg with the matching property group. 1155 * 1156 * The caller of _walk_template_instances() MUST check if the passed parameters 1157 * inst and svc match the fields pw_inst and pw_svc in the resulting 1158 * pg_tmpl_walk_t and call the destructor for the unmatching objects. The walker 1159 * may silently drop them if the template definition is in the restarter or in 1160 * the global instance. 1161 */ 1162 static void 1163 _walk_template_instances(scf_service_t *svc, scf_instance_t *inst, 1164 scf_snapshot_t *snap, walk_template_inst_func_t *func, 1165 pg_tmpl_walk_t *p, int flag) 1166 { 1167 scf_instance_t *tmpl_inst = NULL; 1168 scf_handle_t *h; 1169 int ret; 1170 char *tg = NULL; 1171 1172 assert(svc != NULL || inst != NULL); 1173 assert(svc == NULL || inst == NULL); 1174 1175 if (inst != NULL) 1176 h = scf_instance_handle(inst); 1177 else 1178 h = scf_service_handle(svc); 1179 if (h == NULL) 1180 goto done; 1181 1182 /* First, use supplied service or instance */ 1183 p->pw_target = SCF_TM_TARGET_THIS; 1184 ret = func(svc, inst, p); 1185 switch (ret) { 1186 case SCF_WALK_NEXT: 1187 break; 1188 case SCF_WALK_DONE: 1189 /* 1190 * Check that the template scoping matches and if not, 1191 * continue. 1192 */ 1193 assert(p->pw_pg != NULL); 1194 tg = _scf_read_single_astring_from_pg(p->pw_pg, 1195 SCF_PROPERTY_TM_TARGET); 1196 if (tg == NULL || /* scf_error() was set */ 1197 (strcmp(tg, SCF_TM_TARGET_INSTANCE) != 0 && 1198 strcmp(tg, SCF_TM_TARGET_THIS) != 0 && 1199 (flag & SCF_PG_TMPL_FLAG_EXACT) != 1200 SCF_PG_TMPL_FLAG_EXACT)) { 1201 scf_pg_destroy(p->pw_pg); 1202 p->pw_pg = NULL; 1203 if (tg != NULL) { 1204 free(tg); 1205 tg = NULL; 1206 break; 1207 } 1208 } 1209 /*FALLTHROUGH*/ 1210 case SCF_WALK_ERROR: 1211 goto done; 1212 /*NOTREACHED*/ 1213 default: 1214 assert(0); 1215 abort(); 1216 } 1217 1218 /* Next the restarter. */ 1219 p->pw_target = SCF_TM_TARGET_DELEGATE; 1220 tmpl_inst = _get_restarter_inst(h, svc, inst, snap); 1221 if (tmpl_inst != NULL) { 1222 ret = func(NULL, tmpl_inst, p); 1223 switch (ret) { 1224 case SCF_WALK_NEXT: 1225 break; 1226 case SCF_WALK_DONE: 1227 /* 1228 * Check that the template scoping matches and if not, 1229 * continue. 1230 */ 1231 assert(p->pw_pg != NULL); 1232 tg = _scf_read_single_astring_from_pg(p->pw_pg, 1233 SCF_PROPERTY_TM_TARGET); 1234 if (tg == NULL || /* scf_error() was set */ 1235 strcmp(tg, SCF_TM_TARGET_DELEGATE) != 0) { 1236 scf_pg_destroy(p->pw_pg); 1237 p->pw_pg = NULL; 1238 if (tg != NULL) { 1239 free(tg); 1240 tg = NULL; 1241 break; 1242 } 1243 } 1244 /*FALLTHROUGH*/ 1245 case SCF_WALK_ERROR: 1246 goto done; 1247 /*NOTREACHED*/ 1248 default: 1249 assert(0); 1250 abort(); 1251 } 1252 } 1253 1254 p->pw_target = SCF_TM_TARGET_ALL; 1255 scf_instance_destroy(tmpl_inst); 1256 tmpl_inst = _get_global_inst(h); 1257 if (tmpl_inst != NULL) { 1258 ret = func(NULL, tmpl_inst, p); 1259 switch (ret) { 1260 case SCF_WALK_NEXT: 1261 break; 1262 case SCF_WALK_DONE: 1263 /* 1264 * Check that the template scoping matches and if not, 1265 * continue. 1266 */ 1267 assert(p->pw_pg != NULL); 1268 tg = _scf_read_single_astring_from_pg(p->pw_pg, 1269 SCF_PROPERTY_TM_TARGET); 1270 if (tg == NULL || /* scf_error() was set */ 1271 strcmp(tg, SCF_TM_TARGET_ALL) != 0) { 1272 scf_pg_destroy(p->pw_pg); 1273 p->pw_pg = NULL; 1274 if (tg != NULL) { 1275 free(tg); 1276 tg = NULL; 1277 break; 1278 } 1279 } 1280 /*FALLTHROUGH*/ 1281 case SCF_WALK_ERROR: 1282 goto done; 1283 /*NOTREACHED*/ 1284 default: 1285 assert(0); 1286 abort(); 1287 } 1288 } 1289 1290 done: 1291 free(tg); 1292 if (ret != SCF_WALK_DONE) 1293 scf_instance_destroy(tmpl_inst); 1294 p->pw_target = NULL; 1295 } 1296 1297 /* 1298 * _get_pg() returns 0 on success and -1 on failure. Sets scf_error() 1299 * on failure. 1300 * SCF_ERROR_BACKEND_ACCESS 1301 * SCF_ERROR_CONNECTION_BROKEN 1302 * SCF_ERROR_DELETED 1303 * SCF_ERROR_HANDLE_MISMATCH 1304 * SCF_ERROR_INTERNAL 1305 * SCF_ERROR_INVALID_ARGUMENT 1306 * name is not a valid property group. 1307 * SCF_ERROR_NO_RESOURCES 1308 * SCF_ERROR_NOT_BOUND 1309 * SCF_ERROR_NOT_FOUND 1310 * SCF_ERROR_NOT_SET 1311 */ 1312 static int 1313 _get_pg(scf_service_t *svc, scf_instance_t *inst, 1314 const scf_snapshot_t *snap, const char *name, scf_propertygroup_t *pg) 1315 { 1316 int ret; 1317 1318 assert(svc != NULL || inst != NULL); 1319 assert(svc == NULL || inst == NULL); 1320 assert(pg != NULL); 1321 1322 if (inst != NULL) 1323 ret = scf_instance_get_pg_composed(inst, snap, name, pg); 1324 else 1325 ret = scf_service_get_pg(svc, name, pg); 1326 1327 return (ret); 1328 } 1329 1330 /* 1331 * Returns SCF_WALK_NEXT for not found, SCF_WALK_ERROR for error, 1332 * and SCF_WALK_DONE for found. 1333 * On error, destroy pg and set it to NULL. 1334 * 1335 * Sets scf_error() if SCF_WALK_ERROR is returned to _BACKEND_ACCESS, 1336 * _CONNECTION_BROKEN, _INTERNAL, _INVALID_ARGUMENT (name is not a 1337 * valid property group), _NO_RESOURCES, or _NOT_BOUND. 1338 */ 1339 static int 1340 _lookup_pg(scf_service_t *svc, scf_instance_t *inst, 1341 const scf_snapshot_t *snap, const char *name, scf_propertygroup_t *pg) 1342 { 1343 int ret; 1344 1345 ret = _get_pg(svc, inst, snap, name, pg); 1346 1347 if (ret == 0) { 1348 return (SCF_WALK_DONE); 1349 } else { 1350 switch (scf_error()) { 1351 case SCF_ERROR_NOT_FOUND: 1352 case SCF_ERROR_DELETED: 1353 return (SCF_WALK_NEXT); 1354 1355 case SCF_ERROR_BACKEND_ACCESS: 1356 case SCF_ERROR_CONNECTION_BROKEN: 1357 case SCF_ERROR_INTERNAL: 1358 case SCF_ERROR_INVALID_ARGUMENT: 1359 case SCF_ERROR_NOT_BOUND: 1360 case SCF_ERROR_NO_RESOURCES: 1361 scf_pg_destroy(pg); 1362 pg = NULL; 1363 return (SCF_WALK_ERROR); 1364 1365 case SCF_ERROR_NOT_SET: 1366 case SCF_ERROR_HANDLE_MISMATCH: 1367 default: 1368 assert(0); 1369 abort(); 1370 } 1371 } 1372 1373 /*NOTREACHED*/ 1374 } 1375 1376 /* 1377 * If match, return 0. If no match, return 1. If error, return -1. 1378 * On error set scf_error() to _BACKEND_ACCESS, _CONNECTION_BROKEN, 1379 * _HANDLE_DESTROYED, _INTERNAL, _NO_MEMORY, _NO_RESOURCES, _NOT_BOUND, 1380 * _NOT_SET (property group specified by pg is not set), _PERMISSION_DENIED, 1381 * or _TEMPLATE_INVALID (target property is not SCF_TYPE_ASTRING or has 1382 * more than one value). 1383 */ 1384 static int 1385 check_target_match(scf_propertygroup_t *pg, const char *target) 1386 { 1387 char *pg_target; 1388 int ret = 0; 1389 1390 pg_target = _scf_read_single_astring_from_pg(pg, 1391 SCF_PROPERTY_TM_TARGET); 1392 if (pg_target == NULL) { 1393 switch (scf_error()) { 1394 case SCF_ERROR_DELETED: 1395 case SCF_ERROR_NOT_FOUND: 1396 return (1); 1397 1398 case SCF_ERROR_CONSTRAINT_VIOLATED: 1399 case SCF_ERROR_TYPE_MISMATCH: 1400 (void) scf_set_error( 1401 SCF_ERROR_TEMPLATE_INVALID); 1402 /*FALLTHROUGH*/ 1403 1404 case SCF_ERROR_BACKEND_ACCESS: 1405 case SCF_ERROR_CONNECTION_BROKEN: 1406 case SCF_ERROR_HANDLE_DESTROYED: 1407 case SCF_ERROR_INTERNAL: 1408 case SCF_ERROR_NO_RESOURCES: 1409 case SCF_ERROR_NOT_BOUND: 1410 case SCF_ERROR_PERMISSION_DENIED: 1411 return (-1); 1412 1413 case SCF_ERROR_NOT_SET: 1414 case SCF_ERROR_INVALID_ARGUMENT: 1415 default: 1416 assert(0); 1417 abort(); 1418 } 1419 /*NOTREACHED*/ 1420 } 1421 1422 /* For a desired target of 'this', check for 'this' and 'instance'. */ 1423 if ((strcmp(target, SCF_TM_TARGET_INSTANCE) == 0 || 1424 strcmp(target, SCF_TM_TARGET_THIS) == 0) && 1425 (strcmp(pg_target, SCF_TM_TARGET_INSTANCE) == 0 || 1426 strcmp(pg_target, SCF_TM_TARGET_THIS) == 0)) { 1427 goto cleanup; 1428 } 1429 1430 if (strcmp(target, SCF_TM_TARGET_DELEGATE) == 0 && 1431 strcmp(pg_target, SCF_TM_TARGET_DELEGATE) == 0) { 1432 goto cleanup; 1433 } 1434 1435 if (strcmp(target, SCF_TM_TARGET_ALL) == 0 && 1436 strcmp(pg_target, SCF_TM_TARGET_ALL) == 0) { 1437 goto cleanup; 1438 } 1439 1440 ret = 1; 1441 cleanup: 1442 free(pg_target); 1443 return (ret); 1444 } 1445 1446 /* 1447 * Check if a matching template property group exists for each of: 1448 * name and type, name only, type only, and completely wildcarded 1449 * template. 1450 * 1451 * Both pg_name and pg_type are optional. 1452 * 1453 * Returns NULL on failure, sets scf_error(): 1454 * SCF_ERROR_BACKEND_ACCESS 1455 * SCF_ERROR_CONNECTION_BROKEN 1456 * SCF_ERROR_DELETED 1457 * SCF_ERROR_HANDLE_DESTROYED 1458 * SCF_ERROR_INTERNAL 1459 * SCF_ERROR_INVALID_ARGUMENT 1460 * can't combine the _tmpl_pg_name arguments and get a reasonable 1461 * length name, or pg_name is not a valid property group. 1462 * SCF_ERROR_NO_MEMORY 1463 * SCF_ERROR_NO_RESOURCES 1464 * SCF_ERROR_NOT_BOUND 1465 * SCF_ERROR_NOT_FOUND 1466 * Property doesn't exist or exists and has no value. 1467 * SCF_ERROR_PERMISSION_DENIED 1468 * SCF_ERROR_TEMPLATE_INVALID 1469 * target property is not SCF_TYPE_ASTRING or has more than one value. 1470 */ 1471 static scf_propertygroup_t * 1472 _find_template_pg_match(scf_service_t *svc, scf_instance_t *inst, 1473 const scf_snapshot_t *snap, const char *pg_name, const char *pg_type, 1474 const char *target, char **tmpl_pg_name) 1475 { 1476 int ret, r; 1477 scf_propertygroup_t *pg = NULL; 1478 scf_handle_t *h; 1479 scf_iter_t *iter; 1480 char *name, *type; 1481 1482 assert(inst != NULL || svc != NULL); 1483 assert(inst == NULL || svc == NULL); 1484 1485 if (inst != NULL) 1486 h = scf_instance_handle(inst); 1487 else 1488 h = scf_service_handle(svc); 1489 if (h == NULL) { 1490 return (NULL); 1491 } 1492 1493 if ((pg = scf_pg_create(h)) == NULL || 1494 (iter = scf_iter_create(h)) == NULL) { 1495 assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT); 1496 scf_pg_destroy(pg); 1497 return (NULL); 1498 } 1499 1500 /* 1501 * We're going to walk through the possible pg templates that 1502 * could match the supplied name and type. We do this 1503 * by explicit name lookups when possible to avoid having to 1504 * keep track of a most-explicit-match during iteration. 1505 */ 1506 1507 /* First look for a template with name and type set and matching. */ 1508 *tmpl_pg_name = _tmpl_pg_name(pg_name, pg_type, 1); 1509 if (*tmpl_pg_name == NULL) 1510 goto fail; 1511 ret = _lookup_pg(svc, inst, snap, *tmpl_pg_name, pg); 1512 if (ret != SCF_WALK_NEXT) { 1513 if (pg != NULL) { 1514 if ((r = check_target_match(pg, target)) == 0) 1515 goto done; 1516 else if (r == -1) 1517 goto fail; 1518 } else { 1519 goto done; 1520 } 1521 } 1522 free(*tmpl_pg_name); 1523 1524 /* 1525 * Need to search on a name-only match before searching on 1526 * type matches. 1527 */ 1528 1529 *tmpl_pg_name = _tmpl_pg_name(pg_name, NULL, 0); 1530 if (*tmpl_pg_name == NULL) 1531 goto fail; 1532 ret = _lookup_pg(svc, inst, snap, *tmpl_pg_name, pg); 1533 if (ret != SCF_WALK_NEXT) { 1534 if (pg != NULL) { 1535 if ((r = check_target_match(pg, target)) == 0) 1536 goto done; 1537 else if (r == -1) 1538 goto fail; 1539 } else { 1540 goto done; 1541 } 1542 } 1543 free(*tmpl_pg_name); 1544 1545 /* Next, see if there's an "nt" template where the type matches. */ 1546 if (pg_type != NULL && pg_name == NULL) { 1547 if (inst != NULL) 1548 ret = scf_iter_instance_pgs_typed_composed(iter, inst, 1549 snap, SCF_GROUP_TEMPLATE_PG_PATTERN); 1550 else 1551 ret = scf_iter_service_pgs_typed(iter, svc, 1552 SCF_GROUP_TEMPLATE_PG_PATTERN); 1553 1554 if (ret != 0) { 1555 if (ismember(scf_error(), errors_server)) { 1556 goto fail; 1557 } else { 1558 assert(0); 1559 abort(); 1560 } 1561 } 1562 1563 while ((ret = scf_iter_next_pg(iter, pg)) == 1) { 1564 /* Make sure this is a name and type specified pg. */ 1565 name = _scf_read_single_astring_from_pg(pg, 1566 SCF_PROPERTY_TM_NAME); 1567 if (name == NULL) 1568 continue; 1569 type = _scf_read_single_astring_from_pg(pg, 1570 SCF_PROPERTY_TM_TYPE); 1571 if (type == NULL) { 1572 free(name); 1573 continue; 1574 } 1575 if (strcmp(pg_type, type) == 0 && 1576 check_target_match(pg, target) == 0) { 1577 *tmpl_pg_name = name; 1578 free(type); 1579 goto done; 1580 } 1581 free(type); 1582 free(name); 1583 } 1584 if (ret == -1) { 1585 if (ismember(scf_error(), errors_server)) { 1586 goto fail; 1587 } else { 1588 assert(0); 1589 abort(); 1590 } 1591 } 1592 } 1593 1594 *tmpl_pg_name = _tmpl_pg_name(NULL, pg_type, 0); 1595 if (*tmpl_pg_name == NULL) 1596 goto fail; 1597 ret = _lookup_pg(svc, inst, snap, *tmpl_pg_name, pg); 1598 if (ret != SCF_WALK_NEXT) { 1599 if (pg != NULL) { 1600 if ((r = check_target_match(pg, target)) == 0) 1601 goto done; 1602 else if (r == -1) 1603 goto fail; 1604 } else { 1605 goto done; 1606 } 1607 } 1608 free(*tmpl_pg_name); 1609 1610 *tmpl_pg_name = _tmpl_pg_name(NULL, NULL, 0); 1611 if (*tmpl_pg_name == NULL) 1612 goto fail; 1613 ret = _lookup_pg(svc, inst, snap, *tmpl_pg_name, pg); 1614 if (ret != SCF_WALK_NEXT) { 1615 if (pg != NULL) { 1616 if ((r = check_target_match(pg, target)) == 0) 1617 goto done; 1618 else if (r == -1) 1619 goto fail; 1620 } else { 1621 goto done; 1622 } 1623 } 1624 1625 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 1626 fail: 1627 scf_pg_destroy(pg); 1628 if (*tmpl_pg_name != NULL) 1629 free(*tmpl_pg_name); 1630 *tmpl_pg_name = NULL; 1631 pg = NULL; 1632 done: 1633 if (ret == SCF_WALK_ERROR) 1634 free(*tmpl_pg_name); 1635 scf_iter_destroy(iter); 1636 return (pg); 1637 } 1638 1639 /* 1640 * Finds the pg match in either the supplied service or instance. 1641 * Returns SCF_WALK_ERROR, SCF_WALK_NEXT, or SCF_WALK_DONE. 1642 * If returning SCF_WALK_ERROR, sets scf_error(): 1643 * SCF_ERROR_BACKEND_ACCESS 1644 * SCF_ERROR_CONNECTION_BROKEN 1645 * SCF_ERROR_DELETED 1646 * SCF_ERROR_HANDLE_DESTROYED 1647 * SCF_ERROR_INTERNAL 1648 * SCF_ERROR_INVALID_ARGUMENT 1649 * The snaphot is not a valid snapshot name, 1650 * or can't create a reasonable property group template name. 1651 * SCF_ERROR_NO_MEMORY 1652 * SCF_ERROR_NO_RESOURCES 1653 * SCF_ERROR_NOT_BOUND 1654 * SCF_ERROR_NOT_FOUND 1655 * Property doesn't exist or exists and has no value. 1656 * SCF_ERROR_PERMISSION_DENIED 1657 * SCF_ERROR_TEMPLATE_INVALID 1658 * target property is not SCF_TYPE_ASTRING or has more than one value. 1659 */ 1660 static int 1661 find_pg_match(scf_service_t *svc, scf_instance_t *inst, pg_tmpl_walk_t *p) 1662 { 1663 scf_snapshot_t *tmpl_snap = NULL; 1664 scf_propertygroup_t *pg; 1665 scf_handle_t *h; 1666 char *tmpl_pg_name; 1667 1668 assert(svc != NULL || inst != NULL); 1669 assert(svc == NULL || inst == NULL); 1670 1671 if (inst != NULL) 1672 h = scf_instance_handle(inst); 1673 else 1674 h = scf_service_handle(svc); 1675 if (h == NULL) 1676 return (SCF_WALK_ERROR); 1677 1678 if (p->pw_snapname != NULL) { 1679 if (_get_snapshot(inst, p->pw_snapname, &tmpl_snap) == -1) 1680 return (SCF_WALK_ERROR); 1681 } 1682 pg = _find_template_pg_match(svc, inst, tmpl_snap, p->pw_pgname, 1683 p->pw_pgtype, p->pw_target, &tmpl_pg_name); 1684 1685 if (pg != NULL) { 1686 p->pw_snap = tmpl_snap; 1687 p->pw_pg = pg; 1688 p->pw_tmpl_pgname = tmpl_pg_name; 1689 p->pw_inst = inst; 1690 p->pw_svc = svc; 1691 return (SCF_WALK_DONE); 1692 } 1693 1694 scf_snapshot_destroy(tmpl_snap); 1695 return (SCF_WALK_NEXT); 1696 } 1697 1698 /* 1699 * return 0 on success and -1 on failure. 1700 * SCF_ERROR_CONNECTION_BROKEN 1701 * SCF_ERROR_DELETED 1702 * SCF_ERROR_HANDLE_DESTROYED 1703 * SCF_ERROR_HANDLE_MISMATCH 1704 * SCF_ERROR_INTERNAL 1705 * SCF_ERROR_INVALID_ARGUMENT 1706 * FMRI argument, snapshot name, pg_name, or pg is invalid. 1707 * SCF_ERROR_NO_MEMORY 1708 * SCF_ERROR_NO_RESOURCES 1709 * SCF_ERROR_NOT_BOUND 1710 * SCF_ERROR_NOT_FOUND 1711 * SCF_ERROR_NOT_SET 1712 */ 1713 int 1714 scf_tmpl_get_by_pg(scf_propertygroup_t *pg, scf_pg_tmpl_t *pg_tmpl, int flags) 1715 { 1716 char *fmribuf = NULL, *snapbuf = NULL, *pg_name = NULL, *pg_type = NULL; 1717 int ret; 1718 ssize_t fbufsz = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH) + 1; 1719 ssize_t nbufsz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1; 1720 ssize_t tbufsz = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH) + 1; 1721 scf_instance_t *inst = NULL; 1722 scf_snaplevel_t *snaplvl = NULL; 1723 scf_service_t *svc = NULL; 1724 scf_handle_t *h; 1725 scf_snapshot_t *snap = NULL; 1726 pg_tmpl_walk_t *p = NULL; 1727 1728 assert(fbufsz != 0 && nbufsz != 0 && tbufsz != 0); 1729 1730 scf_tmpl_pg_reset(pg_tmpl); 1731 1732 if ((h = scf_pg_handle(pg)) == NULL) 1733 return (-1); 1734 1735 if ((inst = scf_instance_create(h)) == NULL || 1736 (svc = scf_service_create(h)) == NULL || 1737 (snaplvl = scf_snaplevel_create(h)) == NULL) { 1738 goto fail; 1739 } 1740 1741 if ((fmribuf = malloc(fbufsz)) == NULL || 1742 (pg_name = malloc(nbufsz)) == NULL || 1743 (pg_type = malloc(tbufsz)) == NULL || 1744 (p = calloc(1, sizeof (pg_tmpl_walk_t))) == NULL) { 1745 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1746 goto fail; 1747 } 1748 1749 if (scf_pg_get_name(pg, pg_name, nbufsz) < 0) { 1750 goto fail; 1751 } 1752 1753 if (scf_pg_get_type(pg, pg_type, tbufsz) < 0) { 1754 goto fail; 1755 } 1756 p->pw_pgname = pg_name; 1757 p->pw_pgtype = pg_type; 1758 1759 ret = scf_pg_get_parent_snaplevel(pg, snaplvl); 1760 if (ret == -1) { 1761 switch (scf_error()) { 1762 case SCF_ERROR_CONSTRAINT_VIOLATED: 1763 /* Parent type doesn't match. Keep looking. */ 1764 break; 1765 1766 case SCF_ERROR_DELETED: 1767 case SCF_ERROR_NOT_BOUND: 1768 case SCF_ERROR_NOT_SET: 1769 /* Pass these back to the caller. */ 1770 goto fail; 1771 1772 case SCF_ERROR_HANDLE_MISMATCH: 1773 default: 1774 assert(0); 1775 abort(); 1776 } 1777 1778 /* 1779 * No snapshot. We'll use 'editing' by default since 1780 * snap and snapbuf are NULL. 1781 */ 1782 p->pw_snapname = NULL; 1783 1784 } else { 1785 if ((snap = scf_snapshot_create(h)) == NULL) { 1786 goto fail; 1787 } 1788 1789 ret = scf_snaplevel_get_parent(snaplvl, snap); 1790 if (ret == -1) { 1791 if (ismember(scf_error(), errors_server)) { 1792 goto fail; 1793 } else { 1794 assert(0); 1795 abort(); 1796 } 1797 } 1798 1799 /* Grab snapshot name while we're here. */ 1800 if ((snapbuf = malloc(nbufsz)) == NULL) { 1801 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1802 goto fail; 1803 } 1804 if (scf_snapshot_get_name(snap, snapbuf, nbufsz) < 0) { 1805 if (ismember(scf_error(), errors_server)) { 1806 goto fail; 1807 } else { 1808 assert(0); 1809 abort(); 1810 } 1811 } 1812 p->pw_snapname = snapbuf; 1813 1814 ret = scf_snapshot_get_parent(snap, inst); 1815 if (ret == -1) { 1816 if (ismember(scf_error(), errors_server)) { 1817 goto fail; 1818 } else { 1819 assert(0); 1820 abort(); 1821 } 1822 } 1823 1824 _walk_template_instances(NULL, inst, snap, 1825 (walk_template_inst_func_t *)find_pg_match, p, flags); 1826 } 1827 1828 /* No snapshot parent. Go looking for instance parent. */ 1829 if (snapbuf == NULL) { 1830 /* First look for instance parent. */ 1831 ret = scf_pg_get_parent_instance(pg, inst); 1832 if (ret == 0) { 1833 _walk_template_instances(NULL, inst, snap, 1834 (walk_template_inst_func_t *)find_pg_match, 1835 p, flags); 1836 /* OK, check for service parent */ 1837 } else if (ret == -1 && 1838 scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) { 1839 ret = scf_pg_get_parent_service(pg, svc); 1840 if (ret == 0) { 1841 _walk_template_instances(svc, NULL, snap, 1842 (walk_template_inst_func_t *)find_pg_match, 1843 p, flags); 1844 } else { 1845 switch (scf_error()) { 1846 case SCF_ERROR_CONSTRAINT_VIOLATED: 1847 (void) scf_set_error( 1848 SCF_ERROR_NOT_FOUND); 1849 /*FALLTHROUGH*/ 1850 1851 case SCF_ERROR_CONNECTION_BROKEN: 1852 case SCF_ERROR_DELETED: 1853 case SCF_ERROR_HANDLE_MISMATCH: 1854 case SCF_ERROR_NOT_BOUND: 1855 case SCF_ERROR_NOT_SET: 1856 goto fail; 1857 1858 default: 1859 assert(0); 1860 abort(); 1861 } 1862 } 1863 } else { 1864 goto fail; 1865 } 1866 } 1867 1868 if (p->pw_pg != NULL) { 1869 pg_tmpl->pt_h = h; 1870 pg_tmpl->pt_pg = p->pw_pg; 1871 pg_tmpl->pt_inst = p->pw_inst; 1872 /* we may get a different instance back */ 1873 if (p->pw_inst != inst) 1874 scf_instance_destroy(inst); 1875 pg_tmpl->pt_snap = p->pw_snap; 1876 pg_tmpl->pt_svc = p->pw_svc; 1877 /* we may get a different service back */ 1878 if (p->pw_svc != svc) 1879 scf_service_destroy(svc); 1880 pg_tmpl->pt_populated = 1; 1881 free(p->pw_tmpl_pgname); 1882 ret = 0; 1883 goto done; 1884 } 1885 1886 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 1887 1888 fail: 1889 ret = -1; 1890 scf_instance_destroy(inst); 1891 scf_service_destroy(svc); 1892 done: 1893 scf_snapshot_destroy(snap); 1894 free(snapbuf); 1895 free(fmribuf); 1896 free(pg_name); 1897 free(pg_type); 1898 free(p); 1899 scf_snaplevel_destroy(snaplvl); 1900 return (ret); 1901 } 1902 1903 /* 1904 * int scf_tmpl_get_by_pg_name() 1905 * 1906 * Get a template by a combination of the name and type. Either name 1907 * or type can be null, which indicates a wildcard. flags may be 1908 * SCF_PG_TMPL_FLAG_CURRENT (use current properties rather than 1909 * the defined or running snapshot), and SCF_PG_TMPL_FLAG_EXACT (match 1910 * only templates defined by the FMRI in question, not by its restarter 1911 * or globally). Returns 0 on success and -1 on error, and sets 1912 * scf_error() to: 1913 * SCF_ERROR_BACKEND_ACCESS 1914 * SCF_ERROR_CONNECTION_BROKEN 1915 * The connection to the repository was lost. 1916 * SCF_ERROR_DELETED 1917 * The instance has been deleted. 1918 * SCF_ERROR_HANDLE_DESTROYED 1919 * SCF_ERROR_INTERNAL 1920 * SCF_ERROR_INVALID_ARGUMENT 1921 * FMRI isn't valid, pg_name is too long to look for a template, or 1922 * snapshot specified isn't a valid name 1923 * SCF_ERROR_NO_MEMORY 1924 * SCF_ERROR_NO_RESOURCES 1925 * The server does not have adequate resources to complete the request. 1926 * SCF_ERROR_NOT_BOUND 1927 * The handle is not currently bound. 1928 * SCF_ERROR_NOT_FOUND 1929 * Object matching FMRI doesn't exist in the repository, or snapshot 1930 * doesn't exist. 1931 */ 1932 int 1933 scf_tmpl_get_by_pg_name(const char *fmri, const char *snapshot, 1934 const char *pg_name, const char *pg_type, scf_pg_tmpl_t *pg_tmpl, int flags) 1935 { 1936 scf_instance_t *inst = NULL; 1937 scf_service_t *svc = NULL; 1938 scf_snapshot_t *snap = NULL; 1939 pg_tmpl_walk_t *p = NULL; 1940 scf_handle_t *h; 1941 int ret; 1942 1943 assert(pg_tmpl != NULL); 1944 h = pg_tmpl->pt_h; 1945 assert(h != NULL); 1946 1947 scf_tmpl_pg_reset(pg_tmpl); 1948 1949 if ((inst = scf_instance_create(h)) == NULL || 1950 (svc = scf_service_create(h)) == NULL) { 1951 goto fail; 1952 } 1953 1954 p = calloc(1, sizeof (pg_tmpl_walk_t)); 1955 if (p == NULL) { 1956 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1957 goto fail; 1958 } 1959 1960 ret = scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL, 1961 NULL, SCF_DECODE_FMRI_EXACT); 1962 if (ret == 0) { 1963 scf_service_destroy(svc); 1964 svc = NULL; 1965 } else if (ret != 0 && 1966 scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) { 1967 ret = scf_handle_decode_fmri(h, fmri, NULL, svc, 1968 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT); 1969 if (ret == 0) { 1970 scf_instance_destroy(inst); 1971 inst = NULL; 1972 } 1973 } 1974 if (ret != 0) { 1975 if (ismember(scf_error(), errors_server)) { 1976 goto fail; 1977 } else switch (scf_error()) { 1978 case SCF_ERROR_CONSTRAINT_VIOLATED: 1979 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 1980 goto fail; 1981 1982 case SCF_ERROR_INVALID_ARGUMENT: 1983 case SCF_ERROR_NOT_FOUND: 1984 goto fail; 1985 1986 case SCF_ERROR_HANDLE_MISMATCH: 1987 case SCF_ERROR_NOT_SET: 1988 default: 1989 assert(0); 1990 abort(); 1991 } 1992 } 1993 1994 assert(svc == NULL || inst == NULL); 1995 assert(svc != NULL || inst != NULL); 1996 1997 /* If we have a service fmri, snapshot is ignored. */ 1998 if (inst != NULL) { 1999 if (snapshot == NULL || strcmp(snapshot, "running") == 0 || 2000 (flags & SCF_PG_TMPL_FLAG_CURRENT) == 2001 SCF_PG_TMPL_FLAG_CURRENT) { 2002 if (_get_snapshot(inst, NULL, &snap) == -1) 2003 goto fail; 2004 } else { 2005 if (_get_snapshot(inst, snapshot, &snap) == -1) { 2006 goto fail; 2007 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 2008 goto fail; 2009 } 2010 } 2011 } 2012 2013 p->pw_snapname = snapshot; 2014 p->pw_pgname = pg_name; 2015 p->pw_pgtype = pg_type; 2016 2017 /* 2018 * For each of instance, restarter, global 2019 * - check for a tm_pg_pattern_nt_<name> matching type 2020 * - check for a tm_pg_pattern_t_<type> matching type 2021 * - check for any tm_pg_pattern_ 2022 * Currently plan to return the most specific match only. 2023 */ 2024 _walk_template_instances(svc, inst, snap, 2025 (walk_template_inst_func_t *)find_pg_match, p, flags); 2026 2027 if (p->pw_pg != NULL) { 2028 pg_tmpl->pt_h = h; 2029 pg_tmpl->pt_pg = p->pw_pg; 2030 pg_tmpl->pt_inst = p->pw_inst; 2031 /* we may get a different instance back */ 2032 if (p->pw_inst != inst) 2033 scf_instance_destroy(inst); 2034 pg_tmpl->pt_snap = p->pw_snap; 2035 pg_tmpl->pt_svc = p->pw_svc; 2036 /* we may get a different service back */ 2037 if (p->pw_svc != svc) 2038 scf_service_destroy(svc); 2039 pg_tmpl->pt_populated = 1; 2040 scf_snapshot_destroy(snap); 2041 free(p->pw_tmpl_pgname); 2042 free(p); 2043 return (0); 2044 } 2045 2046 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 2047 fail: 2048 free(p); 2049 scf_instance_destroy(inst); 2050 scf_service_destroy(svc); 2051 scf_snapshot_destroy(snap); 2052 return (-1); 2053 } 2054 2055 /* 2056 * Returns NULL on failure, sets scf_error() to _CONNECTION_BROKEN, 2057 * _DELETED, _NO_RESOURCES, or _NOT_BOUND. 2058 */ 2059 static scf_iter_t * 2060 _get_svc_or_inst_iter(scf_handle_t *h, scf_pg_tmpl_t *t) 2061 { 2062 scf_iter_t *iter; 2063 int ret; 2064 2065 assert(t->pt_svc != NULL || t->pt_inst != NULL); 2066 assert(t->pt_svc == NULL || t->pt_inst == NULL); 2067 2068 if ((iter = scf_iter_create(h)) == NULL) { 2069 return (NULL); 2070 } 2071 2072 /* Iterate on property groups of type template_pg_pattern */ 2073 2074 if (t->pt_inst != NULL) 2075 ret = scf_iter_instance_pgs_typed_composed(iter, 2076 t->pt_inst, t->pt_snap, 2077 SCF_GROUP_TEMPLATE_PG_PATTERN); 2078 if (t->pt_svc != NULL) 2079 ret = scf_iter_service_pgs_typed(iter, t->pt_svc, 2080 SCF_GROUP_TEMPLATE_PG_PATTERN); 2081 2082 if (ret != 0) { 2083 if (ismember(scf_error(), errors_server)) { 2084 scf_iter_destroy(iter); 2085 return (NULL); 2086 } else { 2087 assert(0); 2088 abort(); 2089 } 2090 } 2091 2092 return (iter); 2093 } 2094 2095 /* 2096 * Returns NULL on failure, sets scf_error() to: 2097 * SCF_ERROR_BACKEND_ACCESS 2098 * SCF_ERROR_CONNECTION_BROKEN 2099 * SCF_ERROR_DELETED 2100 * SCF_HANDLE_DESTROYED 2101 * SCF_ERROR_INTERNAL 2102 * SCF_ERROR_INVALID_ARGUMENT 2103 * Handle argument is NULL, or snaphot is not a valid snapshot name. 2104 * SCF_ERROR_NO_MEMORY 2105 * SCF_ERROR_NO_RESOURCES 2106 * SCF_ERROR_NOT_BOUND 2107 * SCF_ERROR_NOT_FOUND 2108 */ 2109 static scf_iter_t * 2110 _get_next_iterator(scf_handle_t *h, scf_pg_tmpl_t *t, const char *snapshot, 2111 int exact) 2112 { 2113 scf_iter_t *iter = NULL; 2114 ssize_t limit; 2115 2116 limit = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1; 2117 assert(limit != 0); 2118 2119 /* 2120 * Check what level we last iterated on: none, service, 2121 * restarter, or global. Make sure that if one in the middle 2122 * doesn't exist, we move on to the next entity. 2123 * 2124 * Before we drop any references to pt_inst or pt_svc we must 2125 * destroy them so we don't leak them. 2126 */ 2127 do { 2128 switch (t->pt_iter_last) { 2129 case SCF__TMPL_ITER_NONE: 2130 t->pt_iter_last = SCF__TMPL_ITER_INST; 2131 if (t->pt_inst != t->pt_orig_inst) 2132 scf_instance_destroy(t->pt_inst); 2133 t->pt_inst = t->pt_orig_inst; 2134 if (t->pt_svc != t->pt_orig_svc) 2135 scf_service_destroy(t->pt_svc); 2136 t->pt_svc = t->pt_orig_svc; 2137 break; 2138 2139 case SCF__TMPL_ITER_INST: 2140 /* 2141 * Don't go any further than the specified instance 2142 * if exact was set. 2143 */ 2144 if (exact == 1) { 2145 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 2146 goto fail; 2147 } 2148 t->pt_iter_last = SCF__TMPL_ITER_RESTARTER; 2149 if (t->pt_inst != t->pt_orig_inst) 2150 scf_instance_destroy(t->pt_inst); 2151 t->pt_inst = _get_restarter_inst(h, t->pt_orig_svc, 2152 t->pt_orig_inst, t->pt_snap); 2153 scf_service_destroy(t->pt_svc); 2154 t->pt_svc = NULL; 2155 break; 2156 2157 case SCF__TMPL_ITER_RESTARTER: 2158 t->pt_iter_last = SCF__TMPL_ITER_GLOBAL; 2159 if (t->pt_inst != t->pt_orig_inst) 2160 scf_instance_destroy(t->pt_inst); 2161 t->pt_inst = _get_global_inst(h); 2162 scf_service_destroy(t->pt_svc); 2163 t->pt_svc = NULL; 2164 break; 2165 2166 case SCF__TMPL_ITER_GLOBAL: 2167 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 2168 return (NULL); 2169 2170 default: 2171 assert(0); 2172 abort(); 2173 } 2174 } while (t->pt_inst == NULL && t->pt_svc == NULL); 2175 2176 /* Set pt_snap to the snapshot for this instance */ 2177 if (t->pt_inst != NULL) { 2178 scf_snapshot_destroy(t->pt_snap); 2179 if (_get_snapshot(t->pt_inst, snapshot, 2180 &t->pt_snap) == -1) 2181 goto fail; 2182 } 2183 2184 2185 iter = _get_svc_or_inst_iter(h, t); 2186 fail: 2187 return (iter); 2188 } 2189 2190 /* 2191 * scf_pg_tmpl_t *scf_tmpl_pg_create(scf_handle_t *) 2192 * 2193 * Returns NULL on failure, sets scf_error() to _INVALID_ARGUMENT 2194 * or _NO_MEMORY. 2195 */ 2196 scf_pg_tmpl_t * 2197 scf_tmpl_pg_create(scf_handle_t *handle) 2198 { 2199 scf_pg_tmpl_t *pg_tmpl = NULL; 2200 2201 if (handle == NULL) { 2202 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 2203 return (NULL); 2204 } 2205 pg_tmpl = calloc(1, sizeof (scf_pg_tmpl_t)); 2206 if (pg_tmpl == NULL) 2207 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 2208 else 2209 pg_tmpl->pt_h = handle; 2210 2211 return (pg_tmpl); 2212 } 2213 2214 /* 2215 * Retrieves name or type of a template pg. 2216 * Returns -1 on failure. Sets scf_error(): 2217 * SCF_ERROR_BACKEND_ACCESS 2218 * SCF_ERROR_CONNECTION_BROKEN 2219 * SCF_ERROR_DELETED 2220 * SCF_ERROR_HANDLE_DESTROYED 2221 * SCF_ERROR_INTERNAL 2222 * SCF_ERROR_NO_MEMORY 2223 * SCF_ERROR_NO_RESOURCES 2224 * SCF_ERROR_NOT_BOUND 2225 * SCF_ERROR_PERMISSION_DENIED 2226 * SCF_ERROR_TEMPLATE_INVALID 2227 * pname property is not SCF_TYPE_ASTRING or has more than one value. 2228 */ 2229 static ssize_t 2230 _scf_tmpl_prop_value(scf_propertygroup_t *pg, const char *pname, char **out) 2231 { 2232 assert(strcmp(pname, SCF_PROPERTY_TM_NAME) == 0 || 2233 strcmp(pname, SCF_PROPERTY_TM_TYPE) == 0); 2234 2235 *out = _scf_read_single_astring_from_pg(pg, pname); 2236 2237 if (*out != NULL && *out[0] == '\0') { 2238 (void) scf_set_error(SCF_ERROR_NONE); 2239 free(*out); 2240 *out = strdup(SCF_TMPL_WILDCARD); 2241 if (*out == NULL) 2242 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 2243 } 2244 if (*out == NULL) { 2245 if (ismember(scf_error(), errors_server)) { 2246 return (-1); 2247 } else switch (scf_error()) { 2248 case SCF_ERROR_CONSTRAINT_VIOLATED: 2249 case SCF_ERROR_NOT_FOUND: 2250 case SCF_ERROR_TYPE_MISMATCH: 2251 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID); 2252 return (-1); 2253 2254 case SCF_ERROR_INVALID_ARGUMENT: 2255 case SCF_ERROR_NOT_SET: 2256 default: 2257 assert(0); 2258 abort(); 2259 } 2260 } 2261 2262 return (strlen(*out)); 2263 } 2264 2265 /* 2266 * int scf_tmpl_iter_pgs() 2267 * 2268 * Iterates through the property group templates for the fmri given. 2269 * When t is uninitialized or reset, sets t to the first property group 2270 * template in fmri. On subsequent calls, sets t to the next property group 2271 * template in frmi. 2272 * Returns 1 on success, 0 when no property group templates are left to 2273 * iterate, -1 on error. 2274 * The flags argument may include SCF_PG_TMPL_FLAG_REQUIRED, 2275 * SCF_PG_TMPL_FLAG_CURRENT, and/or SCF_PG_TMPL_FLAG_EXACT. 2276 * 2277 * Returns -1 on error and sets scf_error() to: 2278 * SCF_ERROR_BACKEND_ACCESS 2279 * SCF_ERROR_CONNECTION_BROKEN 2280 * SCF_ERROR_DELETED 2281 * SCF_ERROR_HANDLE_DESTROYED 2282 * SCF_ERROR_INTERNAL 2283 * SCF_ERROR_INVALID_ARGUMENT 2284 * The handle argument is NULL, fmri is invalid, or snapshot is invalid. 2285 * SCF_ERROR_NO_MEMORY 2286 * SCF_ERROR_NO_RESOURCES 2287 * SCF_ERROR_NOT_BOUND 2288 * SCF_ERROR_NOT_FOUND 2289 * SCF_ERROR_PERMISSION_DENIED 2290 */ 2291 int 2292 scf_tmpl_iter_pgs(scf_pg_tmpl_t *t, const char *fmri, const char *snapshot, 2293 const char *type, int flags) 2294 { 2295 scf_handle_t *h; 2296 scf_service_t *svc = NULL; 2297 scf_instance_t *inst = NULL; 2298 scf_propertygroup_t *pg = NULL; 2299 scf_snapshot_t *snap = NULL; 2300 scf_pg_tmpl_t *pg_tmpl = NULL; 2301 int err; 2302 int found = 0; 2303 char *tmpl_type; 2304 uint8_t required; 2305 int ret; 2306 2307 if (t == NULL) { 2308 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 2309 return (-1); 2310 } 2311 2312 h = t->pt_h; 2313 2314 if (t->pt_populated == 0) { 2315 if ((svc = scf_service_create(h)) == NULL || 2316 (inst = scf_instance_create(h)) == NULL || 2317 (pg = scf_pg_create(h)) == NULL) { 2318 goto fail_non_populated; 2319 } 2320 2321 ret = scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL, 2322 NULL, SCF_DECODE_FMRI_EXACT); 2323 if (ret == 0) { 2324 scf_service_destroy(svc); 2325 svc = NULL; 2326 } else if (ret != 0 && 2327 scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) { 2328 ret = scf_handle_decode_fmri(h, fmri, NULL, svc, 2329 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT); 2330 if (ret == 0) { 2331 scf_instance_destroy(inst); 2332 inst = NULL; 2333 } 2334 } 2335 2336 if (ret != 0) { 2337 if (ismember(scf_error(), errors_server)) { 2338 goto fail_non_populated; 2339 } else switch (scf_error()) { 2340 case SCF_ERROR_CONSTRAINT_VIOLATED: 2341 (void) scf_set_error( 2342 SCF_ERROR_INVALID_ARGUMENT); 2343 goto fail_non_populated; 2344 2345 case SCF_ERROR_INVALID_ARGUMENT: 2346 case SCF_ERROR_NOT_FOUND: 2347 goto fail_non_populated; 2348 2349 case SCF_ERROR_HANDLE_MISMATCH: 2350 case SCF_ERROR_NOT_SET: 2351 default: 2352 assert(0); 2353 abort(); 2354 } 2355 } 2356 2357 assert(svc == NULL || inst == NULL); 2358 assert(svc != NULL || inst != NULL); 2359 2360 if (inst != NULL) { 2361 if (snapshot == NULL || 2362 strcmp(snapshot, "running") == 0 || 2363 (flags & SCF_PG_TMPL_FLAG_CURRENT) == 2364 SCF_PG_TMPL_FLAG_CURRENT) { 2365 if (_get_snapshot(inst, NULL, &snap) == -1) 2366 goto fail_non_populated; 2367 } else { 2368 (void) scf_set_error(SCF_ERROR_NONE); 2369 if (_get_snapshot(inst, snapshot, 2370 &snap) == -1) { 2371 goto fail_non_populated; 2372 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 2373 goto fail_non_populated; 2374 } 2375 } 2376 } else { 2377 scf_snapshot_destroy(snap); 2378 snap = NULL; 2379 } 2380 2381 pg_tmpl = t; 2382 pg_tmpl->pt_orig_inst = inst; 2383 pg_tmpl->pt_orig_svc = svc; 2384 pg_tmpl->pt_snap = snap; 2385 pg_tmpl->pt_is_iter = 1; 2386 pg_tmpl->pt_iter_last = SCF__TMPL_ITER_NONE; 2387 pg_tmpl->pt_pg = pg; 2388 pg_tmpl->pt_populated = 1; 2389 } else { 2390 if (t->pt_is_iter != 1) { 2391 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 2392 return (-1); 2393 } 2394 pg_tmpl = t; 2395 assert(pg_tmpl->pt_pg != NULL); 2396 } 2397 2398 if (pg_tmpl->pt_iter == NULL) { 2399 pg_tmpl->pt_iter = _get_next_iterator(h, pg_tmpl, snapshot, 2400 (flags & SCF_PG_TMPL_FLAG_EXACT) ? 1 : 0); 2401 if (pg_tmpl->pt_iter == NULL) { 2402 if (scf_error() == SCF_ERROR_NOT_FOUND) 2403 return (0); 2404 else 2405 return (-1); 2406 } 2407 } 2408 2409 while (found == 0) { 2410 while ((err = scf_iter_next_pg(pg_tmpl->pt_iter, 2411 pg_tmpl->pt_pg)) != 1) { 2412 if (err == -1) { 2413 if (ismember(scf_error(), errors_server)) { 2414 return (-1); 2415 } else switch (scf_error()) { 2416 case SCF_ERROR_HANDLE_MISMATCH: 2417 return (-1); 2418 2419 case SCF_ERROR_NOT_SET: 2420 case SCF_ERROR_INVALID_ARGUMENT: 2421 default: 2422 assert(0); 2423 abort(); 2424 } 2425 } else if (err == 0) { 2426 /* This iteration is done. Get the next one */ 2427 scf_iter_destroy(pg_tmpl->pt_iter); 2428 pg_tmpl->pt_iter = _get_next_iterator(h, 2429 pg_tmpl, snapshot, 2430 (flags & SCF_PG_TMPL_FLAG_EXACT) ? 1 : 0); 2431 if (pg_tmpl->pt_iter == NULL) { 2432 if (scf_error() == SCF_ERROR_NOT_FOUND) 2433 return (0); 2434 else 2435 return (-1); 2436 } 2437 continue; 2438 } else { 2439 assert(0); 2440 abort(); 2441 } 2442 } 2443 2444 /* 2445 * Discard pgs which don't exist at the right scoping. This 2446 * check also makes sure that if we're looking at, for 2447 * example, svc:/system/svc/restarter:default, that we 2448 * don't hand back the same property groups twice. 2449 */ 2450 switch (t->pt_iter_last) { 2451 case SCF__TMPL_ITER_INST: 2452 ret = check_target_match(pg_tmpl->pt_pg, 2453 SCF_TM_TARGET_THIS); 2454 break; 2455 case SCF__TMPL_ITER_RESTARTER: 2456 ret = check_target_match(pg_tmpl->pt_pg, 2457 SCF_TM_TARGET_DELEGATE); 2458 break; 2459 case SCF__TMPL_ITER_GLOBAL: 2460 ret = check_target_match(pg_tmpl->pt_pg, 2461 SCF_TM_TARGET_ALL); 2462 break; 2463 case SCF__TMPL_ITER_NONE: 2464 default: 2465 assert(0); 2466 abort(); 2467 } 2468 2469 if (ret != 0) 2470 continue; 2471 2472 /* 2473 * If walking only required property groups, check if 2474 * the retrieved group is required. 2475 */ 2476 if (flags & SCF_PG_TMPL_FLAG_REQUIRED) { 2477 if (scf_tmpl_pg_required(pg_tmpl, &required) == 0) { 2478 if (required == 0) 2479 continue; 2480 } else { 2481 return (-1); 2482 } 2483 } 2484 2485 /* 2486 * If type != NULL, check if type property matches. If no 2487 * type property exists, consider it a match. 2488 */ 2489 if (type != NULL) { 2490 if (scf_tmpl_pg_type(pg_tmpl, &tmpl_type) != -1) { 2491 if (strcmp(tmpl_type, SCF_TMPL_WILDCARD) 2492 == 0 || strcmp(type, tmpl_type) == 0) { 2493 free(tmpl_type); 2494 break; 2495 } 2496 free(tmpl_type); 2497 } else if (scf_error() == SCF_ERROR_NOT_FOUND || 2498 scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED || 2499 scf_error() == SCF_ERROR_TYPE_MISMATCH) { 2500 break; 2501 } else { 2502 return (-1); 2503 } 2504 } else { 2505 break; 2506 } 2507 } 2508 2509 return (1); 2510 2511 fail_non_populated: 2512 scf_service_destroy(svc); 2513 scf_instance_destroy(inst); 2514 scf_pg_destroy(pg); 2515 scf_snapshot_destroy(snap); 2516 return (-1); 2517 } 2518 2519 void 2520 scf_tmpl_pg_destroy(scf_pg_tmpl_t *t) 2521 { 2522 if (t == NULL) 2523 return; 2524 2525 scf_pg_destroy(t->pt_pg); 2526 scf_instance_destroy(t->pt_inst); 2527 if (t->pt_inst != t->pt_orig_inst) 2528 scf_instance_destroy(t->pt_orig_inst); 2529 scf_snapshot_destroy(t->pt_snap); 2530 scf_service_destroy(t->pt_orig_svc); 2531 if (t->pt_svc != t->pt_orig_svc) 2532 scf_service_destroy(t->pt_svc); 2533 scf_iter_destroy(t->pt_iter); 2534 free(t); 2535 } 2536 2537 void 2538 scf_tmpl_pg_reset(scf_pg_tmpl_t *t) 2539 { 2540 scf_pg_destroy(t->pt_pg); 2541 t->pt_pg = NULL; 2542 2543 scf_instance_destroy(t->pt_inst); 2544 if (t->pt_inst != t->pt_orig_inst) 2545 scf_instance_destroy(t->pt_orig_inst); 2546 t->pt_inst = NULL; 2547 t->pt_orig_inst = NULL; 2548 2549 scf_snapshot_destroy(t->pt_snap); 2550 t->pt_snap = NULL; 2551 2552 scf_service_destroy(t->pt_orig_svc); 2553 if (t->pt_svc != t->pt_orig_svc) 2554 scf_service_destroy(t->pt_svc); 2555 t->pt_orig_svc = NULL; 2556 t->pt_svc = NULL; 2557 2558 scf_iter_destroy(t->pt_iter); 2559 t->pt_iter = NULL; 2560 2561 t->pt_populated = 0; 2562 t->pt_is_iter = 0; 2563 t->pt_iter_last = 0; 2564 2565 /* Do not reset t->pt_h. */ 2566 } 2567 2568 /* 2569 * int scf_tmpl_get_by_prop() 2570 * 2571 * Get the property template given a property group template and property 2572 * name. No flags are currently defined for this function. 2573 * 2574 * Returns NULL on failure, and sets scf_error(): 2575 * SCF_ERROR_BACKEND_ACCESS 2576 * SCF_ERROR_CONNECTION_BROKEN 2577 * SCF_ERROR_DELETED 2578 * SCF_ERROR_HANDLE_DESTROYED 2579 * SCF_ERROR_INTERNAL 2580 * SCF_ERROR_INVALID_ARGUMENT 2581 * SCF_ERROR_NO_MEMORY 2582 * SCF_ERROR_NO_RESOURCES 2583 * SCF_ERROR_NOT_BOUND 2584 * SCF_ERROR_NOT_FOUND 2585 * Template object matching property doesn't exist in the repository. 2586 * SCF_ERROR_TYPE_MISMATCH 2587 * Matching template object is the wrong type in the repository. 2588 */ 2589 int 2590 scf_tmpl_get_by_prop(scf_pg_tmpl_t *t, const char *prop, 2591 scf_prop_tmpl_t *prop_tmpl, int flags) 2592 { 2593 char *tmpl_prop_name; 2594 scf_propertygroup_t *pg = NULL; 2595 char *pg_type; 2596 int found = 0; 2597 2598 if (flags != 0) { 2599 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 2600 return (-1); 2601 } 2602 2603 scf_tmpl_prop_reset(prop_tmpl); 2604 if ((pg = scf_pg_create(scf_pg_handle(t->pt_pg))) == NULL) 2605 return (-1); 2606 2607 tmpl_prop_name = _tmpl_prop_name(prop, t); 2608 if (tmpl_prop_name == NULL) { 2609 assert(scf_error() != SCF_ERROR_NOT_SET); 2610 return (-1); 2611 } 2612 2613 if (_get_pg(t->pt_svc, t->pt_inst, t->pt_snap, 2614 tmpl_prop_name, pg) != 0) { 2615 if (!ismember(scf_error(), errors_server)) { 2616 switch (scf_error()) { 2617 case SCF_ERROR_NOT_FOUND: 2618 case SCF_ERROR_INVALID_ARGUMENT: 2619 break; 2620 2621 case SCF_ERROR_NOT_SET: 2622 case SCF_ERROR_HANDLE_MISMATCH: 2623 default: 2624 assert(0); 2625 abort(); 2626 } 2627 } 2628 } else { 2629 /* 2630 * We've only found a template property group if the type 2631 * is correct. 2632 */ 2633 if ((pg_type = _scf_get_pg_type(pg)) != NULL && 2634 strcmp(pg_type, SCF_GROUP_TEMPLATE_PROP_PATTERN) == 0) 2635 found++; 2636 else 2637 (void) scf_set_error(SCF_ERROR_TYPE_MISMATCH); 2638 2639 2640 free(pg_type); 2641 } 2642 2643 if (found == 0) { 2644 scf_pg_destroy(pg); 2645 free(tmpl_prop_name); 2646 return (-1); 2647 } 2648 2649 prop_tmpl->prt_h = scf_pg_handle(t->pt_pg); 2650 prop_tmpl->prt_t = t; 2651 prop_tmpl->prt_pg = pg; 2652 prop_tmpl->prt_pg_name = tmpl_prop_name; 2653 prop_tmpl->prt_populated = 1; 2654 2655 return (0); 2656 } 2657 2658 /* 2659 * scf_prop_tmpl_t *scf_tmpl_prop_create(scf_handle_t *); 2660 * 2661 * Returns NULL on failure, sets scf_error() to _INVALID_ARGUMENT, or 2662 * _NO_MEMORY. 2663 */ 2664 scf_prop_tmpl_t * 2665 scf_tmpl_prop_create(scf_handle_t *handle) 2666 { 2667 scf_prop_tmpl_t *pt; 2668 2669 if (handle == NULL) { 2670 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 2671 return (NULL); 2672 } 2673 pt = calloc(1, sizeof (scf_prop_tmpl_t)); 2674 if (pt == NULL) 2675 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 2676 else 2677 pt->prt_h = handle; 2678 2679 return (pt); 2680 } 2681 2682 /* 2683 * int scf_tmpl_iter_props() 2684 * 2685 * Iterates over all property templates defined in the specified property 2686 * group template. The iterator state is stored on the property template 2687 * data structure, and the data structure should be allocated with 2688 * scf_tmpl_prop_create(). To continue the iteration, the previously 2689 * returned structure should be passed in as an argument to this function. 2690 * flags can include SCF_PROP_TMPL_FLAG_REQUIRED. The function returns 2691 * 1 when a result was found, and 0 when the iteration is complete. 2692 * 2693 * Returns -1 on failure, and sets scf_error(): 2694 * SCF_ERROR_BACKEND_ACCESS 2695 * SCF_ERROR_CONNECTION_BROKEN 2696 * SCF_ERROR_DELETED 2697 * SCF_ERROR_HANDLE_DESTROYED 2698 * SCF_ERROR_INTERNAL 2699 * SCF_ERROR_INVALID_ARGUMENT 2700 * SCF_ERROR_NO_MEMORY 2701 * SCF_ERROR_NO_RESOURCES 2702 * SCF_ERROR_NOT_BOUND 2703 * SCF_ERROR_PERMISSION_DENIED 2704 * SCF_ERROR_TEMPLATE_INVALID 2705 * Template data is invalid. One of the property templates in this 2706 * pg_tmpl is malformed. 2707 */ 2708 int 2709 scf_tmpl_iter_props(scf_pg_tmpl_t *t, scf_prop_tmpl_t *pt, int flags) 2710 { 2711 scf_prop_tmpl_t *prop_tmpl; 2712 char *pg_pat; 2713 char *pg_name = NULL; 2714 int err; 2715 int ret; 2716 ssize_t size = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1; 2717 uint8_t required; 2718 scf_handle_t *h; 2719 scf_propertygroup_t *pg = NULL; 2720 scf_iter_t *iter = NULL; 2721 2722 assert(size != 0); 2723 if (t == NULL || pt == NULL) { 2724 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 2725 return (-1); 2726 } 2727 2728 assert(t->pt_inst == NULL || t->pt_svc == NULL); 2729 assert(t->pt_inst != NULL || t->pt_svc != NULL); 2730 2731 if ((pg_name = malloc(size)) == NULL) { 2732 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 2733 return (-1); 2734 } 2735 2736 if (pt->prt_populated == 0) { 2737 if ((h = scf_pg_handle(t->pt_pg)) == NULL) 2738 goto fail_non_populated; 2739 2740 if ((pg = scf_pg_create(h)) == NULL || 2741 (iter = scf_iter_create(h)) == NULL) 2742 goto fail_non_populated; 2743 2744 if (t->pt_inst != NULL) 2745 err = scf_iter_instance_pgs_typed_composed(iter, 2746 t->pt_inst, t->pt_snap, 2747 SCF_GROUP_TEMPLATE_PROP_PATTERN); 2748 else if (t->pt_svc != NULL) 2749 err = scf_iter_service_pgs_typed(iter, t->pt_svc, 2750 SCF_GROUP_TEMPLATE_PROP_PATTERN); 2751 2752 if (err != 0) { 2753 if (ismember(scf_error(), errors_server)) { 2754 goto fail_non_populated; 2755 } else switch (scf_error()) { 2756 case SCF_ERROR_INVALID_ARGUMENT: 2757 goto fail_non_populated; 2758 2759 case SCF_ERROR_NOT_SET: 2760 case SCF_ERROR_HANDLE_MISMATCH: 2761 default: 2762 assert(0); 2763 abort(); 2764 } 2765 2766 } 2767 prop_tmpl = pt; 2768 prop_tmpl->prt_t = t; 2769 prop_tmpl->prt_populated = 1; 2770 prop_tmpl->prt_pg = pg; 2771 prop_tmpl->prt_iter = iter; 2772 } else { 2773 prop_tmpl = pt; 2774 } 2775 2776 while ((err = scf_iter_next_pg(prop_tmpl->prt_iter, 2777 prop_tmpl->prt_pg)) > 0) { 2778 /* 2779 * Check if the name matches the appropriate property 2780 * group template name. 2781 */ 2782 pg_pat = _scf_read_single_astring_from_pg(prop_tmpl->prt_pg, 2783 SCF_PROPERTY_TM_PG_PATTERN); 2784 if (pg_pat == NULL) { 2785 if (ismember(scf_error(), errors_server)) { 2786 uu_free(pg_name); 2787 return (-1); 2788 } else switch (scf_error()) { 2789 case SCF_ERROR_NOT_FOUND: 2790 continue; 2791 2792 case SCF_ERROR_CONSTRAINT_VIOLATED: 2793 case SCF_ERROR_TYPE_MISMATCH: 2794 (void) scf_set_error( 2795 SCF_ERROR_TEMPLATE_INVALID); 2796 free(pg_name); 2797 return (-1); 2798 2799 case SCF_ERROR_INVALID_ARGUMENT: 2800 case SCF_ERROR_NOT_SET: 2801 default: 2802 assert(0); 2803 abort(); 2804 } 2805 } 2806 if ((ret = scf_pg_get_name(t->pt_pg, pg_name, size)) <= 0) { 2807 free(pg_pat); 2808 if (ret == 0) 2809 continue; 2810 2811 if (ismember(scf_error(), errors_server)) { 2812 free(pg_name); 2813 return (-1); 2814 } else { 2815 assert(0); 2816 abort(); 2817 } 2818 } 2819 if (strcmp(pg_pat, pg_name) != 0) { 2820 free(pg_pat); 2821 continue; 2822 } 2823 free(pg_pat); 2824 2825 /* 2826 * If walking only required properties, check if 2827 * the retrieved property is required. 2828 */ 2829 if (flags & SCF_PROP_TMPL_FLAG_REQUIRED) { 2830 if (scf_tmpl_prop_required(prop_tmpl, &required) == 0) { 2831 if (required == 0) 2832 continue; 2833 } else { 2834 free(pg_name); 2835 return (-1); 2836 } 2837 } 2838 free(pg_name); 2839 return (0); 2840 } 2841 2842 if (err == -1) { 2843 if (ismember(scf_error(), errors_server)) { 2844 free(pg_name); 2845 return (-1); 2846 } else { 2847 assert(0); 2848 abort(); 2849 } 2850 } else if (err == 0) { 2851 scf_iter_destroy(prop_tmpl->prt_iter); 2852 prop_tmpl->prt_iter = NULL; 2853 prop_tmpl->prt_populated = 0; 2854 } 2855 free(pg_name); 2856 2857 return (1); 2858 2859 fail_non_populated: 2860 free(pg_name); 2861 scf_pg_destroy(pg); 2862 scf_iter_destroy(iter); 2863 return (-1); 2864 } 2865 2866 void 2867 scf_tmpl_prop_destroy(scf_prop_tmpl_t *t) 2868 { 2869 if (t == NULL) 2870 return; 2871 2872 scf_pg_destroy(t->prt_pg); 2873 free(t->prt_pg_name); 2874 free(t->prt_iter); 2875 free(t); 2876 } 2877 2878 void 2879 scf_tmpl_prop_reset(scf_prop_tmpl_t *t) 2880 { 2881 scf_pg_destroy(t->prt_pg); 2882 t->prt_pg = NULL; 2883 2884 free(t->prt_pg_name); 2885 t->prt_pg_name = NULL; 2886 2887 free(t->prt_iter); 2888 t->prt_iter = NULL; 2889 2890 t->prt_populated = 0; 2891 t->prt_h = NULL; 2892 t->prt_t = NULL; 2893 } 2894 2895 /* 2896 * Returns -1 on failure. Sets scf_error(): 2897 * SCF_ERROR_BACKEND_ACCESS 2898 * SCF_ERROR_CONNECTION_BROKEN 2899 * SCF_ERROR_DELETED 2900 * SCF_ERROR_HANDLE_DESTROYED 2901 * SCF_ERROR_INTERNAL 2902 * SCF_ERROR_NO_MEMORY 2903 * SCF_ERROR_NO_RESOURCES 2904 * SCF_ERROR_NOT_BOUND 2905 * SCF_ERROR_PERMISSION_DENIED 2906 * SCF_ERROR_TEMPLATE_INVALID 2907 * The name of the template property group (the pname property) has 2908 * an improper repository format and is not type astring or has 2909 * more than one value. 2910 */ 2911 ssize_t 2912 scf_tmpl_pg_name(const scf_pg_tmpl_t *t, char **out) 2913 { 2914 return (_scf_tmpl_prop_value(t->pt_pg, SCF_PROPERTY_TM_NAME, out)); 2915 } 2916 2917 /* 2918 * returns an allocated string that must be freed 2919 * 2920 * Returns NULL on failure, sets scf_error() to: 2921 * SCF_ERROR_BACKEND_ACCESS 2922 * SCF_ERROR_CONNECTION_BROKEN 2923 * SCF_ERROR_DELETED 2924 * SCF_ERROR_HANDLE_DESTROYED 2925 * SCF_ERROR_INTERNAL 2926 * SCF_ERROR_INVALID_ARGUMENT 2927 * name not a valid property name 2928 * name and locale are too long to make a property name 2929 * SCF_ERROR_NO_MEMORY 2930 * SCF_ERROR_NO_RESOURCES 2931 * SCF_ERROR_NOT_BOUND 2932 * SCF_ERROR_NOT_FOUND 2933 * Property doesn't exist or exists and has no value. 2934 * SCF_ERROR_PERMISSION_DENIED 2935 * SCF_ERROR_TEMPLATE_INVALID 2936 */ 2937 static char * 2938 _read_localized_astring_from_pg(scf_propertygroup_t *pg, const char *name, 2939 const char *locale) 2940 { 2941 char *str; 2942 char *lname_prop; 2943 2944 str = _add_locale_to_name(name, locale); 2945 if (str == NULL) 2946 return (NULL); 2947 lname_prop = _scf_read_single_astring_from_pg(pg, str); 2948 if (lname_prop == NULL) { 2949 free(str); 2950 if (scf_error() != SCF_ERROR_NOT_FOUND) 2951 return (NULL); 2952 str = _add_locale_to_name(name, "C"); 2953 if (str == NULL) 2954 return (NULL); 2955 lname_prop = _scf_read_single_astring_from_pg(pg, str); 2956 } 2957 free(str); 2958 if (lname_prop == NULL) { 2959 if (scf_error() == SCF_ERROR_TYPE_MISMATCH || 2960 scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) 2961 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID); 2962 } 2963 return (lname_prop); 2964 } 2965 2966 /* 2967 * returns an allocated string that must be freed 2968 * 2969 * Returns -1 on failure, sets scf_error() to: 2970 * SCF_ERROR_BACKEND_ACCESS 2971 * SCF_ERROR_CONNECTION_BROKEN 2972 * SCF_ERROR_DELETED 2973 * SCF_ERROR_HANDLE_DESTROYED 2974 * SCF_ERROR_INTERNAL 2975 * SCF_ERROR_INVALID_ARGUMENT 2976 * locale is too long to make a valid property name 2977 * SCF_ERROR_NO_MEMORY 2978 * SCF_ERROR_NO_RESOURCES 2979 * SCF_ERROR_NOT_BOUND 2980 * SCF_ERROR_NOT_FOUND 2981 * Property doesn't exist or exists and has no value. 2982 * SCF_ERROR_PERMISSION_DENIED 2983 * SCF_ERROR_TEMPLATE_INVALID 2984 */ 2985 ssize_t 2986 scf_tmpl_pg_common_name(const scf_pg_tmpl_t *t, const char *locale, char **out) 2987 { 2988 assert(out != NULL); 2989 if ((*out = _read_localized_astring_from_pg(t->pt_pg, 2990 SCF_PROPERTY_TM_COMMON_NAME_PREFIX, locale)) == NULL) 2991 return (-1); 2992 2993 return (strlen(*out)); 2994 } 2995 2996 /* 2997 * returns an allocated string that must be freed 2998 * 2999 * Returns -1 on failure, sets scf_error() to: 3000 * SCF_ERROR_BACKEND_ACCESS 3001 * SCF_ERROR_CONNECTION_BROKEN 3002 * SCF_ERROR_DELETED 3003 * SCF_ERROR_HANDLE_DESTROYED 3004 * SCF_ERROR_INTERNAL 3005 * SCF_ERROR_INVALID_ARGUMENT 3006 * locale is too long to make a valid property name 3007 * SCF_ERROR_NO_MEMORY 3008 * SCF_ERROR_NO_RESOURCES 3009 * SCF_ERROR_NOT_BOUND 3010 * SCF_ERROR_NOT_FOUND 3011 * Property doesn't exist or exists and has no value. 3012 * SCF_ERROR_PERMISSION_DENIED 3013 * SCF_ERROR_TEMPLATE_INVALID 3014 */ 3015 ssize_t 3016 scf_tmpl_pg_description(const scf_pg_tmpl_t *t, const char *locale, char **out) 3017 { 3018 assert(out != NULL); 3019 if ((*out = _read_localized_astring_from_pg(t->pt_pg, 3020 SCF_PROPERTY_TM_DESCRIPTION_PREFIX, locale)) == NULL) 3021 return (-1); 3022 3023 return (strlen(*out)); 3024 } 3025 3026 /* 3027 * Returns -1 on failure. Sets scf_error(): 3028 * SCF_ERROR_BACKEND_ACCESS 3029 * SCF_ERROR_CONNECTION_BROKEN 3030 * SCF_ERROR_DELETED 3031 * SCF_ERROR_HANDLE_DESTROYED 3032 * SCF_ERROR_INTERNAL 3033 * SCF_ERROR_NO_MEMORY 3034 * SCF_ERROR_NO_RESOURCES 3035 * SCF_ERROR_NOT_BOUND 3036 * SCF_ERROR_NOT_FOUND 3037 * 'type' property doesn't exist or exists and has no value. 3038 * SCF_ERROR_PERMISSION_DENIED 3039 * SCF_ERROR_TEMPLATE_INVALID 3040 * 'type' property is not SCF_TYPE_ASTRING or has more than one value. 3041 */ 3042 ssize_t 3043 scf_tmpl_pg_type(const scf_pg_tmpl_t *t, char **out) 3044 { 3045 return (_scf_tmpl_prop_value(t->pt_pg, SCF_PROPERTY_TM_TYPE, out)); 3046 } 3047 3048 /* 3049 * Returns -1 on failure, sets scf_error() to: 3050 * SCF_ERROR_BACKEND_ACCESS 3051 * SCF_ERROR_CONNECTION_BROKEN 3052 * SCF_ERROR_DELETED 3053 * SCF_ERROR_HANDLE_DESTROYED 3054 * SCF_ERROR_INTERNAL 3055 * SCF_ERROR_NO_MEMORY 3056 * SCF_ERROR_NO_RESOURCES 3057 * SCF_ERROR_NOT_BOUND 3058 * SCF_ERROR_PERMISSION_DENIED 3059 * SCF_ERROR_TEMPLATE_INVALID 3060 * required property is not SCF_TYPE_BOOLEAN or has more than one value. 3061 */ 3062 int 3063 scf_tmpl_pg_required(const scf_pg_tmpl_t *t, uint8_t *out) 3064 { 3065 3066 if (_read_single_boolean_from_pg(t->pt_pg, SCF_PROPERTY_TM_REQUIRED, 3067 out) == -1) { 3068 if (ismember(scf_error(), errors_server)) { 3069 return (-1); 3070 } else switch (scf_error()) { 3071 case SCF_ERROR_CONSTRAINT_VIOLATED: 3072 case SCF_ERROR_TYPE_MISMATCH: 3073 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID); 3074 return (-1); 3075 3076 case SCF_ERROR_NOT_FOUND: 3077 *out = 0; 3078 return (0); 3079 3080 case SCF_ERROR_INVALID_ARGUMENT: 3081 default: 3082 assert(0); 3083 abort(); 3084 } 3085 } 3086 3087 return (0); 3088 } 3089 3090 /* 3091 * Returns -1 on failure. Sets scf_error(): 3092 * SCF_ERROR_BACKEND_ACCESS 3093 * SCF_ERROR_CONNECTION_BROKEN 3094 * SCF_ERROR_DELETED 3095 * SCF_ERROR_HANDLE_DESTROYED 3096 * SCF_ERROR_INTERNAL 3097 * SCF_ERROR_NO_MEMORY 3098 * SCF_ERROR_NO_RESOURCES 3099 * SCF_ERROR_NOT_BOUND 3100 * SCF_ERROR_PERMISSION_DENIED 3101 * SCF_ERROR_TEMPLATE_INVALID 3102 * target property is not SCF_TYPE_ASTRING or has more than one value. 3103 */ 3104 ssize_t 3105 scf_tmpl_pg_target(const scf_pg_tmpl_t *t, char **out) 3106 { 3107 *out = _scf_read_single_astring_from_pg(t->pt_pg, 3108 SCF_PROPERTY_TM_TARGET); 3109 3110 if (*out == NULL) { 3111 if (ismember(scf_error(), errors_server)) { 3112 return (-1); 3113 } else switch (scf_error()) { 3114 case SCF_ERROR_CONSTRAINT_VIOLATED: 3115 case SCF_ERROR_NOT_FOUND: 3116 case SCF_ERROR_TYPE_MISMATCH: 3117 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID); 3118 return (-1); 3119 3120 case SCF_ERROR_INVALID_ARGUMENT: 3121 case SCF_ERROR_NOT_SET: 3122 default: 3123 assert(0); 3124 abort(); 3125 } 3126 } 3127 3128 return (strlen(*out)); 3129 } 3130 3131 /* 3132 * Returns -1 on failure. Sets scf_error(): 3133 * SCF_ERROR_BACKEND_ACCESS 3134 * SCF_ERROR_CONNECTION_BROKEN 3135 * SCF_ERROR_DELETED 3136 * SCF_ERROR_HANDLE_DESTROYED 3137 * SCF_ERROR_INTERNAL 3138 * SCF_ERROR_NO_MEMORY 3139 * SCF_ERROR_NO_RESOURCES 3140 * SCF_ERROR_NOT_BOUND 3141 * SCF_ERROR_PERMISSION_DENIED 3142 * SCF_ERROR_TEMPLATE_INVALID 3143 */ 3144 ssize_t 3145 scf_tmpl_prop_name(const scf_prop_tmpl_t *t, char **out) 3146 { 3147 *out = _scf_read_single_astring_from_pg(t->prt_pg, 3148 SCF_PROPERTY_TM_NAME); 3149 3150 if (*out != NULL && *out[0] == '\0') { 3151 free(*out); 3152 *out = NULL; 3153 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID); 3154 } 3155 if (*out == NULL) { 3156 if (ismember(scf_error(), errors_server)) { 3157 return (-1); 3158 } else switch (scf_error()) { 3159 case SCF_ERROR_CONSTRAINT_VIOLATED: 3160 case SCF_ERROR_NOT_FOUND: 3161 case SCF_ERROR_TEMPLATE_INVALID: 3162 case SCF_ERROR_TYPE_MISMATCH: 3163 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID); 3164 return (-1); 3165 3166 case SCF_ERROR_INVALID_ARGUMENT: 3167 case SCF_ERROR_NOT_SET: 3168 default: 3169 assert(0); 3170 abort(); 3171 } 3172 } 3173 3174 return (strlen(*out)); 3175 } 3176 3177 /* 3178 * Returns -1 on failure. Sets scf_error(): 3179 * SCF_ERROR_BACKEND_ACCESS 3180 * SCF_ERROR_CONNECTION_BROKEN 3181 * SCF_ERROR_DELETED 3182 * SCF_ERROR_HANDLE_DESTROYED 3183 * SCF_ERROR_INTERNAL 3184 * SCF_ERROR_NO_MEMORY 3185 * SCF_ERROR_NO_RESOURCES 3186 * SCF_ERROR_NOT_BOUND 3187 * SCF_ERROR_NOT_FOUND 3188 * 'type' property doesn't exist or exists and has no value. 3189 * SCF_ERROR_PERMISSION_DENIED 3190 * SCF_ERROR_TEMPLATE_INVALID 3191 * 'type' property is not SCF_TYPE_ASTRING, has more than one value, 3192 * is SCF_TYPE_INVALID, or is the empty string. 3193 */ 3194 int 3195 scf_tmpl_prop_type(const scf_prop_tmpl_t *t, scf_type_t *out) 3196 { 3197 char *type; 3198 3199 type = _scf_read_single_astring_from_pg(t->prt_pg, 3200 SCF_PROPERTY_TM_TYPE); 3201 if (type != NULL && type[0] == '\0') { 3202 free(type); 3203 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 3204 return (-1); 3205 } 3206 if (type == NULL) { 3207 if (ismember(scf_error(), errors_server)) { 3208 return (-1); 3209 } else switch (scf_error()) { 3210 case SCF_ERROR_CONSTRAINT_VIOLATED: 3211 case SCF_ERROR_TYPE_MISMATCH: 3212 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID); 3213 /*FALLTHROUGH*/ 3214 3215 case SCF_ERROR_NOT_FOUND: 3216 return (-1); 3217 3218 case SCF_ERROR_INVALID_ARGUMENT: 3219 case SCF_ERROR_NOT_SET: 3220 default: 3221 assert(0); 3222 abort(); 3223 } 3224 } 3225 3226 *out = scf_string_to_type(type); 3227 free(type); 3228 3229 if (*out == SCF_TYPE_INVALID) { 3230 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID); 3231 return (-1); 3232 } 3233 3234 return (0); 3235 } 3236 3237 /* 3238 * Returns -1 on failure, sets scf_error() to: 3239 * SCF_ERROR_BACKEND_ACCESS 3240 * SCF_ERROR_CONNECTION_BROKEN 3241 * SCF_ERROR_DELETED 3242 * Property group which represents t was deleted. 3243 * SCF_ERROR_HANDLE_DESTROYED 3244 * SCF_ERROR_INTERNAL 3245 * SCF_ERROR_NO_MEMORY 3246 * SCF_ERROR_NO_RESOURCES 3247 * SCF_ERROR_NOT_BOUND 3248 * SCF_ERROR_PERMISSION_DENIED 3249 * SCF_ERROR_TEMPLATE_INVALID 3250 * required property is not SCF_TYPE_ASTRING has more than one value. 3251 */ 3252 int 3253 scf_tmpl_prop_required(const scf_prop_tmpl_t *t, uint8_t *out) 3254 { 3255 if (_read_single_boolean_from_pg(t->prt_pg, SCF_PROPERTY_TM_REQUIRED, 3256 out) == -1) { 3257 if (ismember(scf_error(), errors_server)) { 3258 return (-1); 3259 } else switch (scf_error()) { 3260 case SCF_ERROR_CONSTRAINT_VIOLATED: 3261 case SCF_ERROR_TYPE_MISMATCH: 3262 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID); 3263 return (-1); 3264 3265 case SCF_ERROR_NOT_FOUND: 3266 *out = 0; 3267 return (0); 3268 3269 case SCF_ERROR_INVALID_ARGUMENT: 3270 case SCF_ERROR_NOT_SET: 3271 default: 3272 assert(0); 3273 abort(); 3274 } 3275 } 3276 3277 return (0); 3278 } 3279 3280 /* 3281 * Returns -1 on failure. Sets scf_error(): 3282 * SCF_ERROR_BACKEND_ACCESS 3283 * SCF_ERROR_CONNECTION_BROKEN 3284 * SCF_ERROR_DELETED 3285 * SCF_ERROR_HANDLE_DESTROYED 3286 * SCF_ERROR_INTERNAL 3287 * SCF_ERROR_NO_MEMORY 3288 * SCF_ERROR_NO_RESOURCES 3289 * SCF_ERROR_NOT_BOUND 3290 * SCF_ERROR_NOT_FOUND 3291 * Property doesn't exist or exists and has no value. 3292 * SCF_ERROR_INVALID_ARGUMENT 3293 * locale is too long to make a property name 3294 * SCF_ERROR_PERMISSION_DENIED 3295 * SCF_ERROR_TEMPLATE_INVALID 3296 * common_name property is not SCF_TYPE_ASTRING has more than one value. 3297 */ 3298 ssize_t 3299 scf_tmpl_prop_common_name(const scf_prop_tmpl_t *t, const char *locale, 3300 char **out) 3301 { 3302 assert(out != NULL); 3303 if ((*out = _read_localized_astring_from_pg(t->prt_pg, 3304 SCF_PROPERTY_TM_COMMON_NAME_PREFIX, locale)) == NULL) 3305 return (-1); 3306 3307 return (strlen(*out)); 3308 } 3309 3310 /* 3311 * Returns -1 on failure. Sets scf_error(): 3312 * SCF_ERROR_BACKEND_ACCESS 3313 * SCF_ERROR_CONNECTION_BROKEN 3314 * SCF_ERROR_DELETED 3315 * SCF_ERROR_HANDLE_DESTROYED 3316 * SCF_ERROR_INTERNAL 3317 * SCF_ERROR_NO_MEMORY 3318 * SCF_ERROR_NO_RESOURCES 3319 * SCF_ERROR_NOT_BOUND 3320 * SCF_ERROR_NOT_FOUND 3321 * Property doesn't exist or exists and has no value. 3322 * SCF_ERROR_INVALID_ARGUMENT 3323 * locale is too long to make a property name 3324 * SCF_ERROR_PERMISSION_DENIED 3325 * SCF_ERROR_TEMPLATE_INVALID 3326 * description property is not SCF_TYPE_ASTRING has more than one value. 3327 */ 3328 ssize_t 3329 scf_tmpl_prop_description(const scf_prop_tmpl_t *t, const char *locale, 3330 char **out) 3331 { 3332 assert(out != NULL); 3333 if ((*out = _read_localized_astring_from_pg(t->prt_pg, 3334 SCF_PROPERTY_TM_DESCRIPTION_PREFIX, locale)) == NULL) 3335 return (-1); 3336 3337 return (strlen(*out)); 3338 } 3339 3340 /* 3341 * Returns -1 on failure. Sets scf_error(): 3342 * SCF_ERROR_BACKEND_ACCESS 3343 * SCF_ERROR_CONNECTION_BROKEN 3344 * SCF_ERROR_DELETED 3345 * SCF_ERROR_HANDLE_DESTROYED 3346 * SCF_ERROR_INTERNAL 3347 * SCF_ERROR_NO_MEMORY 3348 * SCF_ERROR_NO_RESOURCES 3349 * SCF_ERROR_NOT_BOUND 3350 * SCF_ERROR_NOT_FOUND 3351 * Property doesn't exist or exists and has no value. 3352 * SCF_ERROR_INVALID_ARGUMENT 3353 * locale is too long to make a property name 3354 * SCF_ERROR_PERMISSION_DENIED 3355 * SCF_ERROR_TEMPLATE_INVALID 3356 * units property is not SCF_TYPE_ASTRING has more than one value. 3357 */ 3358 ssize_t 3359 scf_tmpl_prop_units(const scf_prop_tmpl_t *t, const char *locale, char **out) 3360 { 3361 assert(out != NULL); 3362 if ((*out = _read_localized_astring_from_pg(t->prt_pg, 3363 SCF_PROPERTY_TM_UNITS_PREFIX, locale)) == NULL) 3364 return (-1); 3365 3366 return (strlen(*out)); 3367 } 3368 3369 /* 3370 * Returns -1 on failure. Sets scf_error(): 3371 * SCF_ERROR_BACKEND_ACCESS 3372 * SCF_ERROR_CONNECTION_BROKEN 3373 * SCF_ERROR_DELETED 3374 * SCF_ERROR_HANDLE_DESTROYED 3375 * SCF_ERROR_INTERNAL 3376 * SCF_ERROR_NO_MEMORY 3377 * SCF_ERROR_NO_RESOURCES 3378 * SCF_ERROR_NOT_BOUND 3379 * SCF_ERROR_PERMISSION_DENIED 3380 * SCF_ERROR_TEMPLATE_INVALID 3381 * visibility property is not SCF_TYPE_ASTRING has more than one value. 3382 */ 3383 int 3384 scf_tmpl_prop_visibility(const scf_prop_tmpl_t *t, uint8_t *out) 3385 { 3386 char *visibility; 3387 3388 visibility = _scf_read_single_astring_from_pg(t->prt_pg, 3389 SCF_PROPERTY_TM_VISIBILITY); 3390 if (visibility == NULL) { 3391 if (ismember(scf_error(), errors_server)) { 3392 return (-1); 3393 } else switch (scf_error()) { 3394 /* prop doesn't exist we take the default value */ 3395 case SCF_ERROR_NOT_FOUND: 3396 *out = SCF_TMPL_VISIBILITY_READWRITE; 3397 return (0); 3398 3399 case SCF_ERROR_CONSTRAINT_VIOLATED: 3400 case SCF_ERROR_TYPE_MISMATCH: 3401 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID); 3402 return (-1); 3403 3404 case SCF_ERROR_INVALID_ARGUMENT: 3405 case SCF_ERROR_NOT_SET: 3406 default: 3407 assert(0); 3408 abort(); 3409 } 3410 } else if (strcmp(visibility, SCF_TM_VISIBILITY_READWRITE) == 0) { 3411 *out = SCF_TMPL_VISIBILITY_READWRITE; 3412 } else if (strcmp(visibility, SCF_TM_VISIBILITY_HIDDEN) == 0) { 3413 *out = SCF_TMPL_VISIBILITY_HIDDEN; 3414 } else if (strcmp(visibility, SCF_TM_VISIBILITY_READONLY) == 0) { 3415 *out = SCF_TMPL_VISIBILITY_READONLY; 3416 } else { 3417 free(visibility); 3418 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID); 3419 return (-1); 3420 } 3421 3422 free(visibility); 3423 return (0); 3424 } 3425 3426 /* 3427 * Return an allocated string containing the value that must be freed 3428 * with free(). 3429 * 3430 * On error set scf_error() _NO_MEMORY, or _NOT_SET (val has not been set 3431 * to a value). 3432 */ 3433 static char * 3434 _scf_value_get_as_string(scf_value_t *val) 3435 { 3436 ssize_t sz = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH) + 1; 3437 char *buf = malloc(sz); 3438 3439 if (buf == NULL) { 3440 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 3441 } else if (scf_value_get_as_string(val, buf, sz) == -1) { 3442 free(buf); 3443 buf = NULL; 3444 } 3445 3446 return (buf); 3447 } 3448 3449 /* 3450 * Returns -1 on failure, sets scf_error() to: 3451 * SCF_ERROR_BACKEND_ACCESS 3452 * SCF_ERROR_CONNECTION_BROKEN 3453 * SCF_ERROR_DELETED 3454 * SCF_ERROR_HANDLE_DESTROYED 3455 * SCF_ERROR_INTERNAL 3456 * SCF_ERROR_NO_MEMORY 3457 * SCF_ERROR_NO_RESOURCES 3458 * SCF_ERROR_NOT_BOUND 3459 * SCF_ERROR_NOT_FOUND 3460 * SCF_ERROR_PERMISSION_DENIED 3461 * SCF_ERROR_TEMPLATE_INVALID 3462 */ 3463 int 3464 scf_tmpl_prop_cardinality(const scf_prop_tmpl_t *t, uint64_t *min, 3465 uint64_t *max) 3466 { 3467 scf_value_t *val_min = NULL; 3468 scf_value_t *val_max = NULL; 3469 int ret = 0; 3470 3471 if (_read_single_value_from_pg(t->prt_pg, 3472 SCF_PROPERTY_TM_CARDINALITY_MIN, &val_min) == 0) { 3473 if (scf_value_get_count(val_min, min) < 0) 3474 goto error; 3475 } else { 3476 if (scf_error() == SCF_ERROR_NOT_FOUND) 3477 *min = 0; 3478 else 3479 goto error; 3480 } 3481 3482 if (_read_single_value_from_pg(t->prt_pg, 3483 SCF_PROPERTY_TM_CARDINALITY_MAX, &val_max) == 0) { 3484 if (scf_value_get_count(val_max, max) < 0) 3485 goto error; 3486 } else { 3487 if (scf_error() == SCF_ERROR_NOT_FOUND) 3488 *max = UINT64_MAX; 3489 else 3490 goto error; 3491 } 3492 goto cleanup; 3493 3494 error: 3495 if (ismember(scf_error(), errors_server)) { 3496 ret = -1; 3497 } else switch (scf_error()) { 3498 case SCF_ERROR_TYPE_MISMATCH: 3499 case SCF_ERROR_CONSTRAINT_VIOLATED: 3500 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID); 3501 /*FALLTHROUGH*/ 3502 3503 case SCF_ERROR_NOT_FOUND: 3504 case SCF_ERROR_TEMPLATE_INVALID: 3505 ret = -1; 3506 break; 3507 3508 case SCF_ERROR_NOT_SET: 3509 case SCF_ERROR_INVALID_ARGUMENT: 3510 default: 3511 assert(0); 3512 abort(); 3513 } 3514 3515 cleanup: 3516 scf_value_destroy(val_min); 3517 scf_value_destroy(val_max); 3518 3519 return (ret); 3520 } 3521 3522 /* 3523 * Returns -1 on failure. Sets scf_error(): 3524 * SCF_ERROR_BACKEND_ACCESS 3525 * SCF_ERROR_CONNECTION_BROKEN 3526 * SCF_ERROR_DELETED 3527 * SCF_ERROR_HANDLE_DESTROYED 3528 * SCF_ERROR_INTERNAL 3529 * SCF_ERROR_NO_MEMORY 3530 * SCF_ERROR_NO_RESOURCES 3531 * SCF_ERROR_NOT_BOUND 3532 * SCF_ERROR_NOT_FOUND 3533 * Property doesn't exist or exists and has no value. 3534 * SCF_ERROR_PERMISSION_DENIED 3535 * SCF_ERROR_TEMPLATE_INVALID 3536 */ 3537 int 3538 scf_tmpl_prop_internal_seps(const scf_prop_tmpl_t *t, scf_values_t *vals) 3539 { 3540 if (_read_astrings_values(t->prt_pg, 3541 SCF_PROPERTY_INTERNAL_SEPARATORS, vals) == NULL) { 3542 if (ismember(scf_error(), errors_server)) { 3543 return (-1); 3544 } else switch (scf_error()) { 3545 case SCF_ERROR_CONSTRAINT_VIOLATED: 3546 case SCF_ERROR_TYPE_MISMATCH: 3547 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID); 3548 /*FALLTHROUGH*/ 3549 3550 case SCF_ERROR_NOT_FOUND: 3551 return (-1); 3552 3553 case SCF_ERROR_INVALID_ARGUMENT: 3554 case SCF_ERROR_NOT_SET: 3555 default: 3556 assert(0); 3557 abort(); 3558 } 3559 } else if (vals->value_count == 0) { 3560 /* property has no value */ 3561 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 3562 scf_values_destroy(vals); 3563 return (-1); 3564 } 3565 3566 return (0); 3567 } 3568 3569 /* 3570 * Returns -1 on failure. Sets scf_error(): 3571 * SCF_ERROR_BACKEND_ACCESS 3572 * SCF_ERROR_CONNECTION_BROKEN 3573 * SCF_ERROR_DELETED 3574 * SCF_ERROR_HANDLE_DESTROYED 3575 * SCF_ERROR_INTERNAL 3576 * SCF_ERROR_NO_MEMORY 3577 * SCF_ERROR_NO_RESOURCES 3578 * SCF_ERROR_NOT_BOUND 3579 * SCF_ERROR_NOT_FOUND 3580 * Property doesn't exist or exists and has no value. 3581 * SCF_ERROR_PERMISSION_DENIED 3582 * SCF_ERROR_TEMPLATE_INVALID 3583 */ 3584 int 3585 scf_tmpl_value_name_constraints(const scf_prop_tmpl_t *t, 3586 scf_values_t *vals) 3587 { 3588 char **ret; 3589 3590 ret = _read_astrings_values(t->prt_pg, 3591 SCF_PROPERTY_TM_CONSTRAINT_NAME, vals); 3592 3593 if (ret == NULL) { 3594 if (ismember(scf_error(), errors_server)) { 3595 return (-1); 3596 } else switch (scf_error()) { 3597 case SCF_ERROR_CONSTRAINT_VIOLATED: 3598 case SCF_ERROR_TYPE_MISMATCH: 3599 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID); 3600 /*FALLTHROUGH*/ 3601 3602 case SCF_ERROR_NOT_FOUND: 3603 return (-1); 3604 3605 case SCF_ERROR_INVALID_ARGUMENT: 3606 case SCF_ERROR_NOT_SET: 3607 default: 3608 assert(0); 3609 abort(); 3610 } 3611 } else if (vals->value_count == 0) { 3612 /* property has no value */ 3613 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 3614 scf_values_destroy(vals); 3615 return (-1); 3616 } 3617 3618 return (0); 3619 } 3620 3621 /* 3622 * Returns NULL on failure. Sets scf_error(): 3623 * Caller is responsible for freeing returned pointer after use. 3624 * SCF_ERROR_CONSTRAINT_VIOLATED 3625 * More tokens than the array size supplied. 3626 * SCF_ERROR_NO_MEMORY 3627 */ 3628 static void * 3629 _separate_by_separator(char *string, const char *sep, char **array, int size) 3630 { 3631 char *str, *token; 3632 char *lasts; 3633 int n = 0; 3634 3635 assert(array != NULL); 3636 assert(string != NULL); 3637 assert(sep != NULL); 3638 assert(size > 0); 3639 3640 str = strdup(string); 3641 if (str == NULL) { 3642 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 3643 return (NULL); 3644 } 3645 3646 if ((array[n] = strtok_r(str, sep, &lasts)) == NULL) { 3647 assert(0); 3648 abort(); 3649 } 3650 3651 n++; 3652 while ((token = strtok_r(NULL, sep, &lasts)) != NULL) { 3653 if (n >= size) { 3654 goto error; 3655 } 3656 array[n] = token; 3657 n++; 3658 } 3659 if (n < size) { 3660 goto error; 3661 } 3662 3663 return (str); 3664 error: 3665 free(str); 3666 (void) scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED); 3667 return (NULL); 3668 } 3669 3670 /* 3671 * check if name is among values of CHOICES_INCLUDE_VALUES 3672 * return 0 if name is present, 1 name is not present, -1 on failure 3673 * SCF_ERROR_BACKEND_ACCESS 3674 * SCF_ERROR_CONNECTION_BROKEN 3675 * SCF_ERROR_DELETED 3676 * SCF_ERROR_HANDLE_DESTROYED 3677 * SCF_ERROR_INTERNAL 3678 * SCF_ERROR_NO_MEMORY 3679 * SCF_ERROR_NO_RESOURCES 3680 * SCF_ERROR_NOT_BOUND 3681 * SCF_ERROR_PERMISSION_DENIED 3682 * SCF_ERROR_TEMPLATE_INVALID 3683 */ 3684 static int 3685 _check_choices_include_values(scf_propertygroup_t *pg, const char *name) 3686 { 3687 int n = 0, r = 1; 3688 char **ret; 3689 scf_values_t vals; 3690 3691 if ((ret = _read_astrings_values(pg, 3692 SCF_PROPERTY_TM_CHOICES_INCLUDE_VALUES, &vals)) == NULL) { 3693 if (ismember(scf_error(), errors_server)) { 3694 return (-1); 3695 } else switch (scf_error()) { 3696 case SCF_ERROR_NOT_FOUND: 3697 return (1); 3698 3699 case SCF_ERROR_TYPE_MISMATCH: 3700 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID); 3701 return (-1); 3702 3703 case SCF_ERROR_INVALID_ARGUMENT: 3704 case SCF_ERROR_NOT_SET: 3705 default: 3706 assert(0); 3707 abort(); 3708 } 3709 } 3710 3711 for (n = 0; n < vals.value_count; ++n) { 3712 if (strcmp(name, ret[n]) == 0) { 3713 r = 0; 3714 break; 3715 } 3716 } 3717 scf_values_destroy(&vals); 3718 return (r); 3719 } 3720 3721 void 3722 scf_count_ranges_destroy(scf_count_ranges_t *ranges) 3723 { 3724 if (ranges == NULL) 3725 return; 3726 3727 ranges->scr_num_ranges = 0; 3728 free(ranges->scr_min); 3729 free(ranges->scr_max); 3730 ranges->scr_min = NULL; 3731 ranges->scr_max = NULL; 3732 } 3733 3734 void 3735 scf_int_ranges_destroy(scf_int_ranges_t *ranges) 3736 { 3737 if (ranges == NULL) 3738 return; 3739 3740 ranges->sir_num_ranges = 0; 3741 free(ranges->sir_min); 3742 free(ranges->sir_max); 3743 ranges->sir_min = NULL; 3744 ranges->sir_max = NULL; 3745 } 3746 3747 /* 3748 * Returns -1 on failure. Sets scf_error(): 3749 * SCF_ERROR_BACKEND_ACCESS 3750 * SCF_ERROR_CONNECTION_BROKEN 3751 * SCF_ERROR_CONSTRAINT_VIOLATED 3752 * SCF_ERROR_DELETED 3753 * SCF_ERROR_HANDLE_DESTROYED 3754 * SCF_ERROR_INTERNAL 3755 * SCF_ERROR_NO_MEMORY 3756 * SCF_ERROR_NO_RESOURCES 3757 * SCF_ERROR_NOT_BOUND 3758 * SCF_ERROR_NOT_FOUND 3759 * Property doesn't exist or exists and has no value. 3760 * SCF_ERROR_PERMISSION_DENIED 3761 * SCF_ERROR_TEMPLATE_INVALID 3762 */ 3763 static int 3764 _scf_tmpl_get_count_ranges(const scf_prop_tmpl_t *t, const char *prop, 3765 scf_count_ranges_t *ranges) 3766 { 3767 scf_values_t vals; 3768 int i = 0; 3769 char **ret; 3770 char *one_range[2]; 3771 char *endptr; 3772 char *str = NULL; 3773 uint64_t *min = NULL; 3774 uint64_t *max = NULL; 3775 3776 assert(ranges != NULL); 3777 if ((ret = _read_astrings_values(t->prt_pg, prop, &vals)) == NULL) 3778 goto error; 3779 if (vals.value_count == 0) { 3780 /* range values are empty */ 3781 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 3782 goto cleanup; 3783 } 3784 3785 min = malloc(vals.value_count * sizeof (uint64_t)); 3786 max = malloc(vals.value_count * sizeof (uint64_t)); 3787 if (min == NULL || max == NULL) { 3788 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 3789 goto cleanup; 3790 } 3791 for (i = 0; i < vals.value_count; ++i) { 3792 /* min and max should be separated by a "," */ 3793 if ((str = _separate_by_separator(ret[i], ",", one_range, 3794 2)) == NULL) 3795 goto cleanup; 3796 errno = 0; 3797 min[i] = strtoull(one_range[0], &endptr, 10); 3798 if (errno != 0 || endptr == one_range[0] || *endptr) { 3799 (void) scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED); 3800 goto cleanup; 3801 } 3802 errno = 0; 3803 max[i] = strtoull(one_range[1], &endptr, 10); 3804 if (errno != 0 || endptr == one_range[1] || *endptr) { 3805 (void) scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED); 3806 goto cleanup; 3807 } 3808 if (min[i] > max[i]) { 3809 (void) scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED); 3810 goto cleanup; 3811 } 3812 free(str); 3813 str = NULL; 3814 } 3815 ranges->scr_num_ranges = vals.value_count; 3816 ranges->scr_min = min; 3817 ranges->scr_max = max; 3818 scf_values_destroy(&vals); 3819 return (0); 3820 cleanup: 3821 free(str); 3822 free(min); 3823 free(max); 3824 scf_values_destroy(&vals); 3825 error: 3826 if (ismember(scf_error(), errors_server)) { 3827 return (-1); 3828 } else switch (scf_error()) { 3829 case SCF_ERROR_TYPE_MISMATCH: 3830 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID); 3831 /*FALLTHROUGH*/ 3832 3833 case SCF_ERROR_CONSTRAINT_VIOLATED: 3834 case SCF_ERROR_NOT_FOUND: 3835 return (-1); 3836 3837 case SCF_ERROR_INVALID_ARGUMENT: 3838 case SCF_ERROR_NOT_SET: 3839 default: 3840 assert(0); 3841 abort(); 3842 } 3843 /*NOTREACHED*/ 3844 } 3845 3846 /* 3847 * Returns -1 on failure. Sets scf_error(): 3848 * SCF_ERROR_BACKEND_ACCESS 3849 * SCF_ERROR_CONNECTION_BROKEN 3850 * SCF_ERROR_CONSTRAINT_VIOLATED 3851 * SCF_ERROR_DELETED 3852 * SCF_ERROR_HANDLE_DESTROYED 3853 * SCF_ERROR_INTERNAL 3854 * SCF_ERROR_NO_MEMORY 3855 * SCF_ERROR_NO_RESOURCES 3856 * SCF_ERROR_NOT_BOUND 3857 * SCF_ERROR_NOT_FOUND 3858 * Property doesn't exist or exists and has no value. 3859 * SCF_ERROR_PERMISSION_DENIED 3860 * SCF_ERROR_TEMPLATE_INVALID 3861 */ 3862 static int 3863 _scf_tmpl_get_int_ranges(const scf_prop_tmpl_t *t, const char *prop, 3864 scf_int_ranges_t *ranges) 3865 { 3866 scf_values_t vals; 3867 int n = 0; 3868 char **ret; 3869 char *one_range[2]; 3870 char *endptr; 3871 char *str = NULL; 3872 int64_t *min = NULL; 3873 int64_t *max = NULL; 3874 3875 assert(ranges != NULL); 3876 if ((ret = _read_astrings_values(t->prt_pg, prop, &vals)) == NULL) 3877 goto error; 3878 if (vals.value_count == 0) { 3879 /* range values are empty */ 3880 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 3881 goto cleanup; 3882 } 3883 3884 min = malloc(vals.value_count * sizeof (int64_t)); 3885 max = malloc(vals.value_count * sizeof (int64_t)); 3886 if (min == NULL || max == NULL) { 3887 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 3888 goto cleanup; 3889 } 3890 while (n < vals.value_count) { 3891 /* min and max should be separated by a "," */ 3892 if ((str = _separate_by_separator(ret[n], ",", one_range, 2)) 3893 == NULL) 3894 goto cleanup; 3895 errno = 0; 3896 min[n] = strtoll(one_range[0], &endptr, 10); 3897 if (errno != 0 || endptr == one_range[0] || *endptr) { 3898 (void) scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED); 3899 goto cleanup; 3900 } 3901 errno = 0; 3902 max[n] = strtoll(one_range[1], &endptr, 10); 3903 if (errno != 0 || endptr == one_range[1] || *endptr) { 3904 (void) scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED); 3905 goto cleanup; 3906 } 3907 if (min[n] > max[n]) { 3908 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID); 3909 goto cleanup; 3910 } 3911 ++n; 3912 free(str); 3913 str = NULL; 3914 } 3915 ranges->sir_num_ranges = vals.value_count; 3916 ranges->sir_min = min; 3917 ranges->sir_max = max; 3918 scf_values_destroy(&vals); 3919 return (0); 3920 cleanup: 3921 free(str); 3922 free(min); 3923 free(max); 3924 scf_values_destroy(&vals); 3925 error: 3926 if (ismember(scf_error(), errors_server)) { 3927 return (-1); 3928 } else switch (scf_error()) { 3929 case SCF_ERROR_TYPE_MISMATCH: 3930 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID); 3931 /*FALLTHROUGH*/ 3932 3933 case SCF_ERROR_CONSTRAINT_VIOLATED: 3934 case SCF_ERROR_NOT_FOUND: 3935 case SCF_ERROR_TEMPLATE_INVALID: 3936 return (-1); 3937 3938 case SCF_ERROR_INVALID_ARGUMENT: 3939 case SCF_ERROR_NOT_SET: 3940 default: 3941 assert(0); 3942 abort(); 3943 } 3944 /*NOTREACHED*/ 3945 } 3946 3947 /* 3948 * Returns -1 on failure. Sets scf_error(): 3949 * SCF_ERROR_BACKEND_ACCESS 3950 * SCF_ERROR_CONNECTION_BROKEN 3951 * SCF_ERROR_CONSTRAINT_VIOLATED 3952 * SCF_ERROR_DELETED 3953 * SCF_ERROR_HANDLE_DESTROYED 3954 * SCF_ERROR_INTERNAL 3955 * SCF_ERROR_NO_MEMORY 3956 * SCF_ERROR_NO_RESOURCES 3957 * SCF_ERROR_NOT_BOUND 3958 * SCF_ERROR_NOT_FOUND 3959 * Property doesn't exist or exists and has no value. 3960 * SCF_ERROR_PERMISSION_DENIED 3961 * SCF_ERROR_TEMPLATE_INVALID 3962 */ 3963 int 3964 scf_tmpl_value_count_range_constraints(const scf_prop_tmpl_t *t, 3965 scf_count_ranges_t *ranges) 3966 { 3967 return (_scf_tmpl_get_count_ranges(t, SCF_PROPERTY_TM_CONSTRAINT_RANGE, 3968 ranges)); 3969 } 3970 3971 int 3972 scf_tmpl_value_int_range_constraints(const scf_prop_tmpl_t *t, 3973 scf_int_ranges_t *ranges) 3974 { 3975 return (_scf_tmpl_get_int_ranges(t, SCF_PROPERTY_TM_CONSTRAINT_RANGE, 3976 ranges)); 3977 } 3978 3979 int 3980 scf_tmpl_value_count_range_choices(const scf_prop_tmpl_t *t, 3981 scf_count_ranges_t *ranges) 3982 { 3983 return (_scf_tmpl_get_count_ranges(t, SCF_PROPERTY_TM_CHOICES_RANGE, 3984 ranges)); 3985 } 3986 3987 int 3988 scf_tmpl_value_int_range_choices(const scf_prop_tmpl_t *t, 3989 scf_int_ranges_t *ranges) 3990 { 3991 return (_scf_tmpl_get_int_ranges(t, SCF_PROPERTY_TM_CHOICES_RANGE, 3992 ranges)); 3993 } 3994 3995 /* 3996 * Returns -1 on failure. Sets scf_error(): 3997 * SCF_ERROR_BACKEND_ACCESS 3998 * SCF_ERROR_CONNECTION_BROKEN 3999 * SCF_ERROR_DELETED 4000 * SCF_ERROR_HANDLE_DESTROYED 4001 * SCF_ERROR_INTERNAL 4002 * SCF_ERROR_NO_MEMORY 4003 * SCF_ERROR_NO_RESOURCES 4004 * SCF_ERROR_NOT_BOUND 4005 * SCF_ERROR_NOT_FOUND 4006 * Property doesn't exist or exists and has no value. 4007 * SCF_ERROR_PERMISSION_DENIED 4008 * SCF_ERROR_TEMPLATE_INVALID 4009 */ 4010 int 4011 scf_tmpl_value_name_choices(const scf_prop_tmpl_t *t, scf_values_t *vals) 4012 { 4013 int c_flag = 0; /* have not read any value yet */ 4014 int r; 4015 char **ret; 4016 4017 /* First, look for explicitly declared choices. */ 4018 if ((ret = _read_astrings_values(t->prt_pg, 4019 SCF_PROPERTY_TM_CHOICES_NAME, vals)) != NULL) { 4020 c_flag = 1; 4021 } else if (scf_error() != SCF_ERROR_NOT_FOUND) { 4022 goto error; 4023 } 4024 4025 /* Next, check for choices included by 'values'. */ 4026 if ((r = _check_choices_include_values(t->prt_pg, "values")) == 0) { 4027 /* read values_name */ 4028 if (c_flag == 1) 4029 /* append values */ 4030 ret = _append_astrings_values(t->prt_pg, 4031 SCF_PROPERTY_TM_VALUES_NAME, vals); 4032 else 4033 /* read values */ 4034 ret = _read_astrings_values(t->prt_pg, 4035 SCF_PROPERTY_TM_VALUES_NAME, vals); 4036 if (ret != NULL) { 4037 c_flag = 1; 4038 } else if (scf_error() != SCF_ERROR_NOT_FOUND) { 4039 goto error; 4040 } 4041 } else if (r == -1) { 4042 goto error; 4043 } 4044 4045 /* Finally check for choices included by 'constraints'. */ 4046 if ((r = _check_choices_include_values(t->prt_pg, "constraints")) == 4047 0) { 4048 /* read constraint_name */ 4049 if (c_flag == 1) 4050 /* append values */ 4051 ret = _append_astrings_values(t->prt_pg, 4052 SCF_PROPERTY_TM_CONSTRAINT_NAME, vals); 4053 else 4054 /* read values */ 4055 ret = _read_astrings_values(t->prt_pg, 4056 SCF_PROPERTY_TM_CONSTRAINT_NAME, vals); 4057 if (ret != NULL) { 4058 c_flag = 1; 4059 } else if (scf_error() != SCF_ERROR_NOT_FOUND) { 4060 goto error; 4061 } 4062 } else if (r == -1) { 4063 goto error; 4064 } 4065 4066 if (c_flag == 0 || vals->value_count == 0) { 4067 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 4068 return (-1); 4069 } 4070 4071 return (0); 4072 4073 error: 4074 if (ismember(scf_error(), errors_server)) { 4075 return (-1); 4076 } else switch (scf_error()) { 4077 case SCF_ERROR_TYPE_MISMATCH: 4078 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID); 4079 return (-1); 4080 4081 case SCF_ERROR_NOT_SET: 4082 case SCF_ERROR_INVALID_ARGUMENT: 4083 default: 4084 assert(0); 4085 abort(); 4086 } 4087 /*NOTREACHED*/ 4088 } 4089 4090 void 4091 scf_values_destroy(scf_values_t *vals) 4092 { 4093 int i; 4094 char **items = NULL; 4095 char **str = NULL; 4096 4097 if (vals == NULL) 4098 return; 4099 4100 str = vals->values_as_strings; 4101 4102 /* free values */ 4103 switch (vals->value_type) { 4104 case SCF_TYPE_BOOLEAN: 4105 free(vals->values.v_boolean); 4106 break; 4107 case SCF_TYPE_COUNT: 4108 free(vals->values.v_count); 4109 break; 4110 case SCF_TYPE_INTEGER: 4111 free(vals->values.v_integer); 4112 break; 4113 case SCF_TYPE_ASTRING: 4114 items = vals->values.v_astring; 4115 str = NULL; 4116 break; 4117 case SCF_TYPE_USTRING: 4118 items = vals->values.v_ustring; 4119 str = NULL; 4120 break; 4121 case SCF_TYPE_OPAQUE: 4122 items = vals->values.v_opaque; 4123 str = NULL; 4124 break; 4125 case SCF_TYPE_TIME: 4126 free(vals->values.v_time); 4127 break; 4128 default: 4129 assert(0); 4130 abort(); 4131 } 4132 for (i = 0; i < vals->value_count; ++i) { 4133 if (items != NULL) 4134 free(items[i]); 4135 if (str != NULL) 4136 free(str[i]); 4137 } 4138 vals->value_count = 0; 4139 free(items); 4140 free(str); 4141 } 4142 4143 /* 4144 * char *_make_value_name() 4145 * 4146 * Construct the prefix for a value common name or value description property. 4147 * It takes the form: 4148 * value_<BASE32 name>_<common_name|description>_ 4149 * This is then combined with a localized suffix by the caller to look 4150 * up the property in the repository: 4151 * value_<BASE32 name>_<common_name|description>_<lang> 4152 * 4153 * Returns NULL on failure. Sets scf_error(): 4154 * SCF_ERROR_INVALID_ARGUMENT 4155 * Name isn't short enough make a value name with. 4156 * SCF_ERROR_NO_MEMORY 4157 */ 4158 static char * 4159 _make_value_name(char *desc_name, const char *value) 4160 { 4161 char *name = NULL; 4162 char *encoded = NULL; 4163 ssize_t sz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1; 4164 4165 name = malloc(sz); 4166 encoded = malloc(sz); 4167 if (name == NULL || encoded == NULL) { 4168 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 4169 free(name); 4170 free(encoded); 4171 return (NULL); 4172 } 4173 4174 if (scf_encode32(value, strlen(value), encoded, sz, NULL, 4175 SCF_ENCODE32_PAD) != 0) { 4176 /* Shouldn't happen. */ 4177 assert(0); 4178 } 4179 4180 (void) strlcpy(name, SCF_PROPERTY_TM_VALUE_PREFIX, sz); 4181 4182 if (strlcat(name, encoded, sz) >= sz) { 4183 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 4184 free(name); 4185 free(encoded); 4186 return (NULL); 4187 } 4188 4189 if (strlcat(name, "_", sz) >= sz) { 4190 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 4191 free(name); 4192 free(encoded); 4193 return (NULL); 4194 } 4195 4196 if (strlcat(name, desc_name, sz) >= sz) { 4197 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 4198 free(name); 4199 free(encoded); 4200 return (NULL); 4201 } 4202 4203 if (strlcat(name, "_", sz) >= sz) { 4204 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 4205 free(name); 4206 free(encoded); 4207 return (NULL); 4208 } 4209 4210 free(encoded); 4211 return (name); 4212 } 4213 4214 /* 4215 * ssize_t scf_tmpl_value_common_name() 4216 * 4217 * Populates "out" with an allocated string containing the value's 4218 * common name. Returns the size of the string on successful return. 4219 * out must be freed with free() on successful return. 4220 * 4221 * Returns -1 on failure, sets scf_error() to: 4222 * SCF_ERROR_BACKEND_ACCESS 4223 * SCF_ERROR_CONNECTION_BROKEN 4224 * SCF_ERROR_DELETED 4225 * Property group was deleted. 4226 * SCF_ERROR_HANDLE_DESTROYED 4227 * SCF_ERROR_INTERNAL 4228 * SCF_ERROR_INVALID_ARGUMENT 4229 * name not a valid property name 4230 * name and locale are too long to make a property name 4231 * SCF_ERROR_NO_MEMORY 4232 * SCF_ERROR_NO_RESOURCES 4233 * SCF_ERROR_NOT_BOUND 4234 * SCF_ERROR_NOT_FOUND 4235 * Property doesn't exist or exists and has no value. 4236 * SCF_ERROR_PERMISSION_DENIED 4237 * SCF_ERROR_TEMPLATE_INVALID 4238 * property is not SCF_TYPE_ASTRING has more than one value. 4239 */ 4240 ssize_t 4241 scf_tmpl_value_common_name(const scf_prop_tmpl_t *t, const char *locale, 4242 const char *value, char **out) 4243 { 4244 char *value_name = NULL; 4245 4246 value_name = _make_value_name("common_name", value); 4247 if (value_name == NULL) 4248 return (-1); 4249 4250 *out = _read_localized_astring_from_pg(t->prt_pg, value_name, locale); 4251 4252 free(value_name); 4253 4254 if (*out == NULL) 4255 return (-1); 4256 4257 return (strlen(*out)); 4258 } 4259 4260 /* 4261 * ssize_t scf_tmpl_value_description() 4262 * 4263 * Populates "out" with an allocated string containing the value's 4264 * description. Returns the size of the string on successful return. 4265 * out must be freed with free() on successful return. 4266 * 4267 * Returns -1 on failure, sets scf_error() to: 4268 * SCF_ERROR_BACKEND_ACCESS 4269 * SCF_ERROR_CONNECTION_BROKEN 4270 * SCF_ERROR_DELETED 4271 * Property group was deleted. 4272 * SCF_ERROR_HANDLE_DESTROYED 4273 * SCF_ERROR_INTERNAL 4274 * SCF_ERROR_INVALID_ARGUMENT 4275 * name not a valid property name 4276 * name and locale are too long to make a property name 4277 * SCF_ERROR_NO_MEMORY 4278 * SCF_ERROR_NO_RESOURCES 4279 * SCF_ERROR_NOT_BOUND 4280 * SCF_ERROR_NOT_FOUND 4281 * Property doesn't exist or exists and has no value. 4282 * SCF_ERROR_PERMISSION_DENIED 4283 * SCF_ERROR_TEMPLATE_INVALID 4284 * property is not SCF_TYPE_ASTRING has more than one value. 4285 */ 4286 ssize_t 4287 scf_tmpl_value_description(const scf_prop_tmpl_t *t, const char *locale, 4288 const char *value, char **out) 4289 { 4290 char *value_name = NULL; 4291 4292 value_name = _make_value_name("description", value); 4293 if (value_name == NULL) 4294 return (-1); 4295 4296 4297 *out = _read_localized_astring_from_pg(t->prt_pg, value_name, locale); 4298 4299 free(value_name); 4300 4301 if (*out == NULL) 4302 return (-1); 4303 4304 return (strlen(*out)); 4305 } 4306 4307 /* 4308 * Templates error messages format, in human readable form. 4309 * Each line is one error item: 4310 * 4311 * prefix error message 4312 * FMRI="err->te_errs->tes_fmri" 4313 * Property group="err->te_pg_name" 4314 * Property name="err->te_prop_name" 4315 * expected value 1="err->te_ev1" 4316 * expected value 2="err->te_ev2" 4317 * actual value="err->te_actual" 4318 * Tempalte source="err->te_tmpl_fmri" 4319 * pg_pattern name="err->tmpl_pg_name" 4320 * pg_pattern type="err->tmpl_pg_type" 4321 * prop_pattern name="err->tmpl_prop_name" 4322 * prop_pattern type="err->tmpl_prop_type" 4323 * 4324 * To add a new error type, include scf_tmpl_error_type_t in libscf.h 4325 * add one entry in em_desc[], and update the functions pointed by the 4326 * _tmpl_error_access array with the new error code. Also, update the 4327 * scf_tmpl_error_* functions to provide access to desired 4328 * scf_tmpl_error_t fields. 4329 * 4330 * To add a new error item, add a new field to scf_tmpl_error_t, a new field 4331 * in _scf_tmpl_error_desc or a new non-error-dependent string, add a new entry 4332 * in _tmpl_error_access array and create the appropriate get_val, get_desc 4333 * functions. 4334 * 4335 * Changes to both the validation logic and the error types and items must 4336 * be coordinated with the code in svccfg to ensure both libscf and svccfg's 4337 * manifest validation validate the same things. 4338 */ 4339 4340 /* 4341 * Container for all template errors on a validated object. 4342 */ 4343 struct scf_tmpl_errors { 4344 int tes_index; 4345 int tes_num_errs; 4346 scf_tmpl_error_t **tes_errs; 4347 int tes_errs_size; 4348 const char *tes_fmri; 4349 const char *tes_prefix; 4350 int tes_flag; /* if set, scf_tmpl_error_destroy */ 4351 /* will free strings in tes_errs */ 4352 }; 4353 4354 /* 4355 * Templates error-dependent labels 4356 */ 4357 struct _scf_tmpl_error_desc { 4358 const char *em_msg; 4359 const char *em_ev1; 4360 const char *em_ev2; 4361 const char *em_actual; 4362 }; 4363 4364 /* 4365 * This array MUST be kept in synch with the template error definition of 4366 * scf_tmpl_error_type_t in libscf.h 4367 */ 4368 static struct _scf_tmpl_error_desc em_desc[] = { 4369 /* SCF_TERR_MISSING_PG */ 4370 { "Required property group missing", "Name of missing property group", 4371 "Type of missing property group", NULL }, 4372 /* SCF_TERR_WRONG_PG_TYPE */ 4373 { "Property group has bad type", "Specified type", NULL, 4374 "Actual type" }, 4375 /* SCF_TERR_MISSING_PROP */ 4376 { "Required property missing", "Name of missing property", NULL, NULL }, 4377 /* SCF_TERR_WRONG_PROP_TYPE */ 4378 { "Property has bad type", "Specified property type", NULL, 4379 "Actual property type" }, 4380 /* SCF_TERR_CARDINALITY_VIOLATION */ 4381 { "Number of property values violates cardinality restriction", 4382 "Cardinality minimum", "Cardinality maximum", 4383 "Actual number of values" }, 4384 /* SCF_TERR_VALUE_CONSTRAINT_VIOLATED */ 4385 { "Property has illegal value", NULL, NULL, "Illegal value" }, 4386 /* SCF_TERR_RANGE_VIOLATION */ 4387 { "Property value is out of range", NULL, NULL, "Actual value" }, 4388 /* SCF_TERR_PG_REDEFINE */ 4389 { "Instance redefines pg_pattern", "Instance pg_pattern name", 4390 "Instance pg_pattern type", NULL }, 4391 /* SCF_TERR_PROP_TYPE_MISMATCH */ 4392 { "Property type and value type mismatch", NULL, NULL, "Value type" }, 4393 /* SCF_TERR_VALUE_OUT_OF_RANGE */ 4394 { "Value is out of range", NULL, NULL, "Value" }, 4395 /* SCF_TERR_INVALID_VALUE */ 4396 { "Value is not valid", NULL, NULL, "Value" }, 4397 /* SCF_TERR_PG_PATTERN_CONFLICT */ 4398 { "Conflicting pg_pattern specifications", "Template source", 4399 "pg_pattern name", "pg_pattern type" }, 4400 /* SCF_TERR_PROP_PATTERN_CONFLICT */ 4401 { "Conflicting prop_pattern specifications", "Template source", 4402 "prop_pattern name", "prop_pattern type" }, 4403 /* SCF_TERR_GENERAL_REDEFINE */ 4404 { "Service or instance pg_pattern redefines a global or restarter " 4405 "pg_pattern", "Template source", "pg_pattern name", 4406 "pg_pattern type" }, 4407 /* SCF_TERR_INCLUDE_VALUES */ 4408 { "Missing constraints or values for include_values element", 4409 "include_values type", NULL, NULL }, 4410 /* SCF_TERR_PG_PATTERN_INCOMPLETE */ 4411 { "Required pg_pattern is missing a name or type attribute", 4412 NULL, NULL, NULL }, 4413 /* SCF_TERR_PROP_PATTERN_INCOMPLETE */ 4414 { "Required prop_pattern is missing a type attribute", 4415 NULL, NULL, NULL } 4416 }; 4417 4418 /* 4419 * Templates non error-dependent labels 4420 */ 4421 static const char *em_fmri = "FMRI"; 4422 static const char *em_pg_name = "Property group"; 4423 static const char *em_prop_name = "Property name"; 4424 static const char *em_tmpl_fmri = "Template source"; 4425 static const char *em_tmpl_pg_name = "pg_pattern name"; 4426 static const char *em_tmpl_pg_type = "pg_pattern type"; 4427 static const char *em_tmpl_prop_name = "prop_pattern name"; 4428 static const char *em_tmpl_prop_type = "prop_pattern type"; 4429 4430 static const char * 4431 _get_fmri_desc(scf_tmpl_error_t *err) 4432 { 4433 switch (err->te_type) { 4434 case SCF_TERR_MISSING_PG: 4435 case SCF_TERR_WRONG_PG_TYPE: 4436 case SCF_TERR_MISSING_PROP: 4437 case SCF_TERR_WRONG_PROP_TYPE: 4438 case SCF_TERR_CARDINALITY_VIOLATION: 4439 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED: 4440 case SCF_TERR_RANGE_VIOLATION: 4441 case SCF_TERR_PG_REDEFINE: 4442 case SCF_TERR_PG_PATTERN_INCOMPLETE: 4443 case SCF_TERR_PROP_PATTERN_INCOMPLETE: 4444 case SCF_TERR_INCLUDE_VALUES: 4445 return (dgettext(TEXT_DOMAIN, em_fmri)); 4446 case SCF_TERR_PROP_TYPE_MISMATCH: 4447 case SCF_TERR_VALUE_OUT_OF_RANGE: 4448 case SCF_TERR_INVALID_VALUE: 4449 case SCF_TERR_PG_PATTERN_CONFLICT: 4450 case SCF_TERR_PROP_PATTERN_CONFLICT: 4451 case SCF_TERR_GENERAL_REDEFINE: 4452 default: 4453 return (NULL); 4454 } 4455 } 4456 4457 static const char * 4458 _get_pg_name_desc(scf_tmpl_error_t *err) 4459 { 4460 switch (err->te_type) { 4461 case SCF_TERR_WRONG_PG_TYPE: 4462 case SCF_TERR_MISSING_PROP: 4463 case SCF_TERR_WRONG_PROP_TYPE: 4464 case SCF_TERR_CARDINALITY_VIOLATION: 4465 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED: 4466 case SCF_TERR_RANGE_VIOLATION: 4467 return (dgettext(TEXT_DOMAIN, em_pg_name)); 4468 case SCF_TERR_MISSING_PG: 4469 case SCF_TERR_PG_REDEFINE: 4470 case SCF_TERR_PROP_TYPE_MISMATCH: 4471 case SCF_TERR_VALUE_OUT_OF_RANGE: 4472 case SCF_TERR_INVALID_VALUE: 4473 case SCF_TERR_PG_PATTERN_CONFLICT: 4474 case SCF_TERR_PROP_PATTERN_CONFLICT: 4475 case SCF_TERR_GENERAL_REDEFINE: 4476 case SCF_TERR_INCLUDE_VALUES: 4477 case SCF_TERR_PG_PATTERN_INCOMPLETE: 4478 case SCF_TERR_PROP_PATTERN_INCOMPLETE: 4479 default: 4480 return (NULL); 4481 } 4482 } 4483 4484 static const char * 4485 _get_prop_name_desc(scf_tmpl_error_t *err) 4486 { 4487 switch (err->te_type) { 4488 case SCF_TERR_WRONG_PROP_TYPE: 4489 case SCF_TERR_CARDINALITY_VIOLATION: 4490 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED: 4491 case SCF_TERR_RANGE_VIOLATION: 4492 return (dgettext(TEXT_DOMAIN, em_prop_name)); 4493 case SCF_TERR_MISSING_PG: 4494 case SCF_TERR_WRONG_PG_TYPE: 4495 case SCF_TERR_MISSING_PROP: 4496 case SCF_TERR_PG_REDEFINE: 4497 case SCF_TERR_PROP_TYPE_MISMATCH: 4498 case SCF_TERR_VALUE_OUT_OF_RANGE: 4499 case SCF_TERR_INVALID_VALUE: 4500 case SCF_TERR_PG_PATTERN_CONFLICT: 4501 case SCF_TERR_PROP_PATTERN_CONFLICT: 4502 case SCF_TERR_GENERAL_REDEFINE: 4503 case SCF_TERR_INCLUDE_VALUES: 4504 case SCF_TERR_PG_PATTERN_INCOMPLETE: 4505 case SCF_TERR_PROP_PATTERN_INCOMPLETE: 4506 default: 4507 return (NULL); 4508 } 4509 } 4510 4511 static const char * 4512 _get_ev1_desc(scf_tmpl_error_t *err) 4513 { 4514 switch (err->te_type) { 4515 case SCF_TERR_MISSING_PG: 4516 case SCF_TERR_WRONG_PG_TYPE: 4517 case SCF_TERR_MISSING_PROP: 4518 case SCF_TERR_WRONG_PROP_TYPE: 4519 case SCF_TERR_CARDINALITY_VIOLATION: 4520 case SCF_TERR_RANGE_VIOLATION: 4521 case SCF_TERR_PG_REDEFINE: 4522 case SCF_TERR_PG_PATTERN_CONFLICT: 4523 case SCF_TERR_PROP_PATTERN_CONFLICT: 4524 case SCF_TERR_GENERAL_REDEFINE: 4525 case SCF_TERR_INCLUDE_VALUES: 4526 return (dgettext(TEXT_DOMAIN, em_desc[err->te_type].em_ev1)); 4527 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED: 4528 case SCF_TERR_PROP_TYPE_MISMATCH: 4529 case SCF_TERR_VALUE_OUT_OF_RANGE: 4530 case SCF_TERR_INVALID_VALUE: 4531 case SCF_TERR_PG_PATTERN_INCOMPLETE: 4532 case SCF_TERR_PROP_PATTERN_INCOMPLETE: 4533 default: 4534 return (NULL); 4535 } 4536 } 4537 4538 static const char * 4539 _get_ev2_desc(scf_tmpl_error_t *err) 4540 { 4541 switch (err->te_type) { 4542 case SCF_TERR_MISSING_PG: 4543 case SCF_TERR_CARDINALITY_VIOLATION: 4544 case SCF_TERR_RANGE_VIOLATION: 4545 case SCF_TERR_PG_REDEFINE: 4546 case SCF_TERR_PG_PATTERN_CONFLICT: 4547 case SCF_TERR_PROP_PATTERN_CONFLICT: 4548 case SCF_TERR_GENERAL_REDEFINE: 4549 return (dgettext(TEXT_DOMAIN, em_desc[err->te_type].em_ev2)); 4550 case SCF_TERR_WRONG_PG_TYPE: 4551 case SCF_TERR_MISSING_PROP: 4552 case SCF_TERR_WRONG_PROP_TYPE: 4553 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED: 4554 case SCF_TERR_PROP_TYPE_MISMATCH: 4555 case SCF_TERR_VALUE_OUT_OF_RANGE: 4556 case SCF_TERR_INVALID_VALUE: 4557 case SCF_TERR_INCLUDE_VALUES: 4558 case SCF_TERR_PG_PATTERN_INCOMPLETE: 4559 case SCF_TERR_PROP_PATTERN_INCOMPLETE: 4560 default: 4561 return (NULL); 4562 } 4563 } 4564 4565 static const char * 4566 _get_actual_desc(scf_tmpl_error_t *err) 4567 { 4568 switch (err->te_type) { 4569 case SCF_TERR_MISSING_PG: 4570 case SCF_TERR_WRONG_PG_TYPE: 4571 case SCF_TERR_WRONG_PROP_TYPE: 4572 case SCF_TERR_CARDINALITY_VIOLATION: 4573 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED: 4574 case SCF_TERR_RANGE_VIOLATION: 4575 case SCF_TERR_PROP_TYPE_MISMATCH: 4576 case SCF_TERR_VALUE_OUT_OF_RANGE: 4577 case SCF_TERR_INVALID_VALUE: 4578 case SCF_TERR_PG_PATTERN_CONFLICT: 4579 case SCF_TERR_PROP_PATTERN_CONFLICT: 4580 case SCF_TERR_GENERAL_REDEFINE: 4581 case SCF_TERR_INCLUDE_VALUES: 4582 return (dgettext(TEXT_DOMAIN, 4583 em_desc[err->te_type].em_actual)); 4584 case SCF_TERR_MISSING_PROP: 4585 case SCF_TERR_PG_REDEFINE: 4586 case SCF_TERR_PG_PATTERN_INCOMPLETE: 4587 case SCF_TERR_PROP_PATTERN_INCOMPLETE: 4588 default: 4589 return (NULL); 4590 } 4591 } 4592 4593 static const char * 4594 _get_tmpl_fmri_desc(scf_tmpl_error_t *err) 4595 { 4596 switch (err->te_type) { 4597 case SCF_TERR_MISSING_PG: 4598 case SCF_TERR_WRONG_PG_TYPE: 4599 case SCF_TERR_MISSING_PROP: 4600 case SCF_TERR_WRONG_PROP_TYPE: 4601 case SCF_TERR_CARDINALITY_VIOLATION: 4602 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED: 4603 case SCF_TERR_RANGE_VIOLATION: 4604 case SCF_TERR_PG_REDEFINE: 4605 case SCF_TERR_PROP_TYPE_MISMATCH: 4606 case SCF_TERR_VALUE_OUT_OF_RANGE: 4607 case SCF_TERR_INVALID_VALUE: 4608 case SCF_TERR_PG_PATTERN_CONFLICT: 4609 case SCF_TERR_PROP_PATTERN_CONFLICT: 4610 case SCF_TERR_GENERAL_REDEFINE: 4611 case SCF_TERR_INCLUDE_VALUES: 4612 case SCF_TERR_PG_PATTERN_INCOMPLETE: 4613 case SCF_TERR_PROP_PATTERN_INCOMPLETE: 4614 return (dgettext(TEXT_DOMAIN, em_tmpl_fmri)); 4615 default: 4616 return (NULL); 4617 } 4618 } 4619 4620 static const char * 4621 _get_tmpl_pg_name_desc(scf_tmpl_error_t *err) 4622 { 4623 switch (err->te_type) { 4624 case SCF_TERR_MISSING_PG: 4625 case SCF_TERR_WRONG_PG_TYPE: 4626 case SCF_TERR_MISSING_PROP: 4627 case SCF_TERR_WRONG_PROP_TYPE: 4628 case SCF_TERR_CARDINALITY_VIOLATION: 4629 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED: 4630 case SCF_TERR_RANGE_VIOLATION: 4631 case SCF_TERR_PG_REDEFINE: 4632 case SCF_TERR_PROP_TYPE_MISMATCH: 4633 case SCF_TERR_VALUE_OUT_OF_RANGE: 4634 case SCF_TERR_INVALID_VALUE: 4635 case SCF_TERR_PG_PATTERN_CONFLICT: 4636 case SCF_TERR_PROP_PATTERN_CONFLICT: 4637 case SCF_TERR_GENERAL_REDEFINE: 4638 case SCF_TERR_INCLUDE_VALUES: 4639 case SCF_TERR_PG_PATTERN_INCOMPLETE: 4640 case SCF_TERR_PROP_PATTERN_INCOMPLETE: 4641 return (dgettext(TEXT_DOMAIN, em_tmpl_pg_name)); 4642 default: 4643 return (NULL); 4644 } 4645 } 4646 4647 static const char * 4648 _get_tmpl_pg_type_desc(scf_tmpl_error_t *err) 4649 { 4650 switch (err->te_type) { 4651 case SCF_TERR_MISSING_PG: 4652 case SCF_TERR_WRONG_PG_TYPE: 4653 case SCF_TERR_MISSING_PROP: 4654 case SCF_TERR_WRONG_PROP_TYPE: 4655 case SCF_TERR_CARDINALITY_VIOLATION: 4656 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED: 4657 case SCF_TERR_RANGE_VIOLATION: 4658 case SCF_TERR_PG_REDEFINE: 4659 case SCF_TERR_PROP_TYPE_MISMATCH: 4660 case SCF_TERR_VALUE_OUT_OF_RANGE: 4661 case SCF_TERR_INVALID_VALUE: 4662 case SCF_TERR_PG_PATTERN_CONFLICT: 4663 case SCF_TERR_PROP_PATTERN_CONFLICT: 4664 case SCF_TERR_GENERAL_REDEFINE: 4665 case SCF_TERR_INCLUDE_VALUES: 4666 case SCF_TERR_PROP_PATTERN_INCOMPLETE: 4667 case SCF_TERR_PG_PATTERN_INCOMPLETE: 4668 return (dgettext(TEXT_DOMAIN, em_tmpl_pg_type)); 4669 default: 4670 return (NULL); 4671 } 4672 } 4673 4674 static const char * 4675 _get_tmpl_prop_name_desc(scf_tmpl_error_t *err) 4676 { 4677 switch (err->te_type) { 4678 case SCF_TERR_MISSING_PROP: 4679 case SCF_TERR_WRONG_PROP_TYPE: 4680 case SCF_TERR_CARDINALITY_VIOLATION: 4681 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED: 4682 case SCF_TERR_RANGE_VIOLATION: 4683 case SCF_TERR_PROP_TYPE_MISMATCH: 4684 case SCF_TERR_VALUE_OUT_OF_RANGE: 4685 case SCF_TERR_INVALID_VALUE: 4686 case SCF_TERR_PROP_PATTERN_CONFLICT: 4687 case SCF_TERR_INCLUDE_VALUES: 4688 case SCF_TERR_PROP_PATTERN_INCOMPLETE: 4689 return (dgettext(TEXT_DOMAIN, em_tmpl_prop_name)); 4690 case SCF_TERR_MISSING_PG: 4691 case SCF_TERR_WRONG_PG_TYPE: 4692 case SCF_TERR_PG_REDEFINE: 4693 case SCF_TERR_PG_PATTERN_CONFLICT: 4694 case SCF_TERR_GENERAL_REDEFINE: 4695 case SCF_TERR_PG_PATTERN_INCOMPLETE: 4696 default: 4697 return (NULL); 4698 } 4699 } 4700 4701 static const char * 4702 _get_tmpl_prop_type_desc(scf_tmpl_error_t *err) 4703 { 4704 switch (err->te_type) { 4705 case SCF_TERR_MISSING_PROP: 4706 case SCF_TERR_WRONG_PROP_TYPE: 4707 case SCF_TERR_CARDINALITY_VIOLATION: 4708 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED: 4709 case SCF_TERR_RANGE_VIOLATION: 4710 case SCF_TERR_PROP_TYPE_MISMATCH: 4711 case SCF_TERR_VALUE_OUT_OF_RANGE: 4712 case SCF_TERR_INVALID_VALUE: 4713 case SCF_TERR_PROP_PATTERN_CONFLICT: 4714 case SCF_TERR_INCLUDE_VALUES: 4715 return (dgettext(TEXT_DOMAIN, em_tmpl_prop_type)); 4716 case SCF_TERR_MISSING_PG: 4717 case SCF_TERR_WRONG_PG_TYPE: 4718 case SCF_TERR_PG_REDEFINE: 4719 case SCF_TERR_PG_PATTERN_CONFLICT: 4720 case SCF_TERR_GENERAL_REDEFINE: 4721 case SCF_TERR_PG_PATTERN_INCOMPLETE: 4722 case SCF_TERR_PROP_PATTERN_INCOMPLETE: 4723 default: 4724 return (NULL); 4725 } 4726 } 4727 4728 static const char * 4729 _get_fmri_val(scf_tmpl_error_t *err) 4730 { 4731 assert(err != NULL && err->te_errs != NULL && 4732 err->te_errs->tes_fmri != NULL); 4733 return (err->te_errs->tes_fmri); 4734 } 4735 4736 static const char * 4737 _get_pg_name_val(scf_tmpl_error_t *err) 4738 { 4739 assert(err != NULL); 4740 return (err->te_pg_name); 4741 } 4742 4743 static const char * 4744 _get_prop_name_val(scf_tmpl_error_t *err) 4745 { 4746 assert(err != NULL); 4747 return (err->te_prop_name); 4748 } 4749 4750 static const char * 4751 _get_ev1_val(scf_tmpl_error_t *err) 4752 { 4753 assert(err != NULL); 4754 return (err->te_ev1); 4755 } 4756 4757 static const char * 4758 _get_ev2_val(scf_tmpl_error_t *err) 4759 { 4760 assert(err != NULL); 4761 return (err->te_ev2); 4762 } 4763 4764 static const char * 4765 _get_actual_val(scf_tmpl_error_t *err) 4766 { 4767 assert(err != NULL); 4768 return (err->te_actual); 4769 } 4770 4771 static const char * 4772 _get_tmpl_fmri_val(scf_tmpl_error_t *err) 4773 { 4774 assert(err != NULL); 4775 return (err->te_tmpl_fmri); 4776 } 4777 4778 static const char * 4779 _get_tmpl_pg_name_val(scf_tmpl_error_t *err) 4780 { 4781 assert(err != NULL); 4782 return (err->te_tmpl_pg_name); 4783 } 4784 4785 static const char * 4786 _get_tmpl_pg_type_val(scf_tmpl_error_t *err) 4787 { 4788 assert(err != NULL); 4789 return (err->te_tmpl_pg_type); 4790 } 4791 4792 static const char * 4793 _get_tmpl_prop_name_val(scf_tmpl_error_t *err) 4794 { 4795 assert(err != NULL); 4796 return (err->te_tmpl_prop_name); 4797 } 4798 4799 static const char * 4800 _get_tmpl_prop_type_val(scf_tmpl_error_t *err) 4801 { 4802 assert(err != NULL); 4803 return (err->te_tmpl_prop_type); 4804 } 4805 4806 /* 4807 * Templates error item retrival functions 4808 */ 4809 typedef const char *(*get_em)(scf_tmpl_error_t *); 4810 4811 /* 4812 * if new items (lines) are added to the templates error messages, 4813 * new entries in this array (and new fuctions) will be required. 4814 */ 4815 static struct _tmpl_error_access { 4816 get_em get_desc; 4817 get_em get_val; 4818 } _tmpl_error_items[] = { 4819 { (get_em)_get_fmri_desc, (get_em)_get_fmri_val }, 4820 { (get_em)_get_pg_name_desc, (get_em)_get_pg_name_val }, 4821 { (get_em)_get_prop_name_desc, (get_em)_get_prop_name_val }, 4822 { (get_em)_get_ev1_desc, (get_em)_get_ev1_val }, 4823 { (get_em)_get_ev2_desc, (get_em)_get_ev2_val }, 4824 { (get_em)_get_actual_desc, (get_em)_get_actual_val }, 4825 { (get_em)_get_tmpl_fmri_desc, (get_em)_get_tmpl_fmri_val }, 4826 { (get_em)_get_tmpl_pg_name_desc, (get_em)_get_tmpl_pg_name_val }, 4827 { (get_em)_get_tmpl_pg_type_desc, (get_em)_get_tmpl_pg_type_val }, 4828 { (get_em)_get_tmpl_prop_name_desc, (get_em)_get_tmpl_prop_name_val }, 4829 { (get_em)_get_tmpl_prop_type_desc, (get_em)_get_tmpl_prop_type_val }, 4830 { NULL } 4831 }; 4832 4833 /* 4834 * Allocate a new scf_tmpl_error_t and add it to the errs list provided. 4835 * Returns NULL on failure. Sets scf_error(): 4836 * SCF_ERROR_NO_MEMORY 4837 */ 4838 static scf_tmpl_error_t * 4839 _create_error(scf_tmpl_errors_t *errs) 4840 { 4841 scf_tmpl_error_t *ret; 4842 scf_tmpl_error_t **saved_errs; 4843 4844 assert(errs != NULL); 4845 ret = calloc(1, sizeof (scf_tmpl_error_t)); 4846 if (ret == NULL) { 4847 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 4848 return (NULL); 4849 } 4850 4851 ret->te_errs = errs; 4852 4853 assert(errs->tes_num_errs <= errs->tes_errs_size); 4854 if (errs->tes_num_errs == errs->tes_errs_size) { 4855 /* Time to grow the pointer array. */ 4856 saved_errs = errs->tes_errs; 4857 errs->tes_errs = calloc(2 * errs->tes_errs_size, 4858 sizeof (scf_tmpl_error_t *)); 4859 if (errs->tes_errs == NULL) { 4860 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 4861 errs->tes_errs = saved_errs; 4862 free(ret); 4863 return (NULL); 4864 } 4865 (void) memcpy(errs->tes_errs, saved_errs, errs->tes_errs_size * 4866 sizeof (scf_tmpl_error_t *)); 4867 errs->tes_errs_size = 2 * errs->tes_errs_size; 4868 free(saved_errs); 4869 } 4870 4871 errs->tes_errs[errs->tes_num_errs] = ret; 4872 errs->tes_num_errs++; 4873 4874 return (ret); 4875 } 4876 4877 /* 4878 * 4879 * If destroy_strings is set, scf_tmpl_errors_destroy will free the 4880 * strings in scf_tmpl_error_t entries. 4881 * 4882 * Returns NULL on failure. Sets scf_error(): 4883 * SCF_ERROR_NO_MEMORY 4884 */ 4885 scf_tmpl_errors_t * 4886 _scf_create_errors(const char *fmri, int destroy_strings) 4887 { 4888 scf_tmpl_errors_t *ret; 4889 int errs_size = 20; 4890 4891 assert(fmri != NULL); 4892 4893 ret = calloc(1, sizeof (scf_tmpl_errors_t)); 4894 if (ret == NULL) { 4895 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 4896 return (NULL); 4897 } 4898 4899 ret->tes_index = 0; 4900 ret->tes_num_errs = 0; 4901 if ((ret->tes_fmri = strdup(fmri)) == NULL) { 4902 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 4903 free(ret); 4904 return (NULL); 4905 } 4906 4907 ret->tes_prefix = strdup(""); 4908 if (ret->tes_prefix == NULL) { 4909 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 4910 free((char *)ret->tes_fmri); 4911 free(ret); 4912 return (NULL); 4913 } 4914 ret->tes_flag = destroy_strings; 4915 4916 /* Make space for a few errors. */ 4917 ret->tes_errs = calloc(errs_size, sizeof (scf_tmpl_error_t *)); 4918 if (ret->tes_errs == NULL) { 4919 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 4920 free((char *)ret->tes_fmri); 4921 free((char *)ret->tes_prefix); 4922 free(ret); 4923 return (NULL); 4924 } 4925 ret->tes_errs_size = errs_size; 4926 4927 return (ret); 4928 } 4929 4930 /* 4931 * return 0 on success, if fails set scf_error() to: 4932 * 4933 * SCF_ERROR_NO_MEMORY 4934 */ 4935 int 4936 _scf_tmpl_error_set_prefix(scf_tmpl_errors_t *errs, const char *prefix) 4937 { 4938 free((void *) errs->tes_prefix); 4939 if (prefix == NULL) 4940 errs->tes_prefix = strdup(""); 4941 else 4942 errs->tes_prefix = strdup(prefix); 4943 if (errs->tes_prefix == NULL) { 4944 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 4945 return (-1); 4946 } 4947 return (0); 4948 } 4949 4950 /* 4951 * 4952 * Returns -1 on failure. Sets scf_error(): 4953 * SCF_ERROR_NO_MEMORY 4954 */ 4955 int 4956 _scf_tmpl_add_error(scf_tmpl_errors_t *errs, scf_tmpl_error_type_t type, 4957 const char *pg_name, const char *prop_name, 4958 const char *ev1, const char *ev2, const char *actual, 4959 const char *tmpl_fmri, const char *tmpl_pg_name, const char *tmpl_pg_type, 4960 const char *tmpl_prop_name, const char *tmpl_prop_type) 4961 { 4962 scf_tmpl_error_t *err; 4963 4964 assert(errs != NULL); 4965 assert(tmpl_fmri != NULL); 4966 4967 err = _create_error(errs); 4968 if (err == NULL) 4969 return (-1); 4970 4971 err->te_type = type; 4972 err->te_pg_name = pg_name; 4973 err->te_prop_name = prop_name; 4974 err->te_ev1 = ev1; 4975 err->te_ev2 = ev2; 4976 err->te_actual = actual; 4977 err->te_tmpl_fmri = tmpl_fmri; 4978 err->te_tmpl_pg_name = tmpl_pg_name; 4979 err->te_tmpl_pg_type = tmpl_pg_type; 4980 err->te_tmpl_prop_name = tmpl_prop_name; 4981 err->te_tmpl_prop_type = tmpl_prop_type; 4982 4983 return (0); 4984 } 4985 4986 /* 4987 * returns an allocated string that must be freed with free() 4988 * string contains converted 64-bit integer value 4989 * flag set for signed values 4990 * if fails return NULL and set scf_error() to: 4991 * SCF_ERROR_NO_MEMORY 4992 */ 4993 static char * 4994 _val_to_string(uint64_t val, int flag) 4995 { 4996 ssize_t sz = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH) + 1; 4997 char *buf; 4998 4999 buf = malloc(sz); 5000 if (buf == NULL) { 5001 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 5002 return (NULL); 5003 } 5004 5005 if (flag == 0) 5006 (void) snprintf(buf, sz, "%" PRIu64, val); 5007 else 5008 (void) snprintf(buf, sz, "%" PRIi64, (int64_t)val); 5009 5010 return (buf); 5011 } 5012 5013 /* 5014 * return 0 on success, -1 on failure. 5015 * set scf_error() to: 5016 * SCF_ERROR_BACKEND_ACCESS 5017 * SCF_ERROR_CONNECTION_BROKEN 5018 * SCF_ERROR_DELETED 5019 * SCF_ERROR_HANDLE_DESTROYED 5020 * SCF_ERROR_INTERNAL 5021 * SCF_ERROR_NO_MEMORY 5022 * SCF_ERROR_NO_RESOURCES 5023 * SCF_ERROR_NOT_BOUND 5024 * SCF_ERROR_PERMISSION_DENIED 5025 * SCF_ERROR_TEMPLATE_INVALID 5026 */ 5027 static int 5028 _add_tmpl_missing_pg_error(scf_tmpl_errors_t *errs, scf_pg_tmpl_t *t) 5029 { 5030 char *ev1 = NULL; 5031 char *ev2 = NULL; 5032 char *t_fmri = NULL; 5033 char *t_pg_name = NULL; 5034 char *t_pg_type = NULL; 5035 5036 if ((t_fmri = _scf_tmpl_get_fmri(t)) == NULL) 5037 return (-1); 5038 if (scf_tmpl_pg_name(t, &t_pg_name) == -1) { 5039 goto cleanup; 5040 } 5041 if (scf_tmpl_pg_type(t, &t_pg_type) == -1) { 5042 goto cleanup; 5043 } 5044 if ((ev1 = strdup(t_pg_name)) == NULL) { 5045 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 5046 goto cleanup; 5047 } 5048 if ((ev2 = strdup(t_pg_type)) == NULL) { 5049 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 5050 goto cleanup; 5051 } 5052 5053 return (_scf_tmpl_add_error(errs, SCF_TERR_MISSING_PG, NULL, NULL, ev1, 5054 ev2, NULL, t_fmri, t_pg_name, t_pg_type, NULL, NULL)); 5055 cleanup: 5056 free(ev1); 5057 free(ev2); 5058 free(t_fmri); 5059 free(t_pg_name); 5060 free(t_pg_type); 5061 return (-1); 5062 } 5063 5064 /* 5065 * return 0 on success, -1 on failure. 5066 * set scf_error() to: 5067 * SCF_ERROR_BACKEND_ACCESS 5068 * SCF_ERROR_CONNECTION_BROKEN 5069 * SCF_ERROR_DELETED 5070 * SCF_ERROR_HANDLE_DESTROYED 5071 * SCF_ERROR_INTERNAL 5072 * SCF_ERROR_NO_MEMORY 5073 * SCF_ERROR_NO_RESOURCES 5074 * SCF_ERROR_NOT_BOUND 5075 * SCF_ERROR_PERMISSION_DENIED 5076 * SCF_ERROR_TEMPLATE_INVALID 5077 */ 5078 static int 5079 _add_tmpl_wrong_pg_type_error(scf_tmpl_errors_t *errs, scf_pg_tmpl_t *t, 5080 scf_propertygroup_t *pg) 5081 { 5082 char *pg_name = NULL; 5083 char *ev1 = NULL; 5084 char *actual = NULL; 5085 char *t_fmri = NULL; 5086 char *t_pg_name = NULL; 5087 char *t_pg_type = NULL; 5088 5089 if ((t_fmri = _scf_tmpl_get_fmri(t)) == NULL) 5090 return (-1); 5091 if ((pg_name = _scf_get_pg_name(pg)) == NULL) 5092 goto cleanup; 5093 if ((actual = _scf_get_pg_type(pg)) == NULL) 5094 goto cleanup; 5095 if (scf_tmpl_pg_name(t, &t_pg_name) == -1) { 5096 goto cleanup; 5097 } 5098 if (scf_tmpl_pg_type(t, &t_pg_type) == -1) { 5099 goto cleanup; 5100 } 5101 if ((ev1 = strdup(t_pg_type)) == NULL) { 5102 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 5103 goto cleanup; 5104 } 5105 5106 return (_scf_tmpl_add_error(errs, SCF_TERR_WRONG_PG_TYPE, pg_name, NULL, 5107 ev1, NULL, actual, t_fmri, t_pg_name, t_pg_type, NULL, NULL)); 5108 cleanup: 5109 free(pg_name); 5110 free(ev1); 5111 free(actual); 5112 free(t_fmri); 5113 free(t_pg_name); 5114 free(t_pg_type); 5115 return (-1); 5116 } 5117 5118 /* 5119 * return 0 on success, -1 on failure. 5120 * set scf_error() to: 5121 * SCF_ERROR_BACKEND_ACCESS 5122 * SCF_ERROR_CONNECTION_BROKEN 5123 * SCF_ERROR_DELETED 5124 * SCF_ERROR_HANDLE_DESTROYED 5125 * SCF_ERROR_INTERNAL 5126 * SCF_ERROR_NO_MEMORY 5127 * SCF_ERROR_NO_RESOURCES 5128 * SCF_ERROR_NOT_BOUND 5129 * SCF_ERROR_PERMISSION_DENIED 5130 * SCF_ERROR_TEMPLATE_INVALID 5131 */ 5132 static int 5133 _add_tmpl_missing_prop_error(scf_tmpl_errors_t *errs, scf_pg_tmpl_t *t, 5134 scf_propertygroup_t *pg, const scf_prop_tmpl_t *pt) 5135 { 5136 char *pg_name = NULL; 5137 char *ev1 = NULL; 5138 char *t_fmri = NULL; 5139 char *t_pg_name = NULL; 5140 char *t_pg_type = NULL; 5141 char *t_prop_name = NULL; 5142 char *t_prop_type = NULL; 5143 5144 if ((t_fmri = _scf_tmpl_get_fmri(t)) == NULL) 5145 return (-1); 5146 if ((pg_name = _scf_get_pg_name(pg)) == NULL) 5147 goto cleanup; 5148 if (scf_tmpl_pg_name(t, &t_pg_name) == -1) { 5149 goto cleanup; 5150 } 5151 if (scf_tmpl_pg_type(t, &t_pg_type) == -1) { 5152 goto cleanup; 5153 } 5154 if (scf_tmpl_prop_name(pt, &t_prop_name) == -1) { 5155 goto cleanup; 5156 } 5157 t_prop_type = _scf_read_tmpl_prop_type_as_string(pt); 5158 if (t_prop_type != NULL && t_prop_type[0] == '\0') { 5159 free(t_prop_type); 5160 t_prop_type = NULL; 5161 } else if (t_prop_type == NULL) { 5162 goto cleanup; 5163 } 5164 if (t_prop_type == NULL) 5165 if ((t_prop_type = strdup(SCF_TMPL_WILDCARD)) == NULL) { 5166 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 5167 goto cleanup; 5168 } 5169 if ((ev1 = strdup(t_prop_name)) == NULL) { 5170 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 5171 goto cleanup; 5172 } 5173 5174 return (_scf_tmpl_add_error(errs, SCF_TERR_MISSING_PROP, pg_name, NULL, 5175 ev1, NULL, NULL, t_fmri, t_pg_name, t_pg_type, t_prop_name, 5176 t_prop_type)); 5177 cleanup: 5178 free(pg_name); 5179 free(ev1); 5180 free(t_fmri); 5181 free(t_pg_name); 5182 free(t_pg_type); 5183 free(t_prop_name); 5184 free(t_prop_type); 5185 return (-1); 5186 } 5187 5188 /* 5189 * return 0 on success, -1 on failure. 5190 * set scf_error() to: 5191 * SCF_ERROR_BACKEND_ACCESS 5192 * SCF_ERROR_CONNECTION_BROKEN 5193 * SCF_ERROR_DELETED 5194 * SCF_ERROR_HANDLE_DESTROYED 5195 * SCF_ERROR_INTERNAL 5196 * SCF_ERROR_NO_MEMORY 5197 * SCF_ERROR_NO_RESOURCES 5198 * SCF_ERROR_NOT_BOUND 5199 * SCF_ERROR_PERMISSION_DENIED 5200 * SCF_ERROR_TEMPLATE_INVALID 5201 */ 5202 static int 5203 _add_tmpl_wrong_prop_type_error(scf_tmpl_errors_t *errs, 5204 scf_propertygroup_t *pg, const scf_prop_tmpl_t *pt, scf_property_t *prop) 5205 { 5206 char *pg_name = NULL; 5207 char *prop_name = NULL; 5208 char *ev1 = NULL; 5209 char *actual = NULL; 5210 char *t_fmri = NULL; 5211 char *t_pg_name = NULL; 5212 char *t_pg_type = NULL; 5213 char *t_prop_name = NULL; 5214 char *t_prop_type = NULL; 5215 5216 if ((t_fmri = _scf_tmpl_get_fmri(pt->prt_t)) == NULL) 5217 return (-1); 5218 if ((pg_name = _scf_get_pg_name(pg)) == NULL) 5219 goto cleanup; 5220 if ((prop_name = _scf_get_prop_name(prop)) == NULL) 5221 goto cleanup; 5222 if ((actual = _scf_get_prop_type(prop)) == NULL) 5223 goto cleanup; 5224 if (scf_tmpl_pg_name(pt->prt_t, &t_pg_name) == -1) { 5225 goto cleanup; 5226 } 5227 if (scf_tmpl_pg_type(pt->prt_t, &t_pg_type) == -1) { 5228 goto cleanup; 5229 } 5230 if (scf_tmpl_prop_name(pt, &t_prop_name) == -1) { 5231 goto cleanup; 5232 } 5233 t_prop_type = _scf_read_tmpl_prop_type_as_string(pt); 5234 if (t_prop_type != NULL && t_prop_type[0] == '\0') { 5235 free(t_prop_type); 5236 t_prop_type = NULL; 5237 } else if (t_prop_type == NULL) { 5238 goto cleanup; 5239 } 5240 if (t_prop_type == NULL) 5241 if ((t_prop_type = strdup(SCF_TMPL_WILDCARD)) == NULL) { 5242 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 5243 goto cleanup; 5244 } 5245 if ((ev1 = strdup(t_prop_type)) == NULL) { 5246 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 5247 goto cleanup; 5248 } 5249 5250 return (_scf_tmpl_add_error(errs, SCF_TERR_WRONG_PROP_TYPE, pg_name, 5251 prop_name, ev1, NULL, actual, t_fmri, t_pg_name, t_pg_type, 5252 t_prop_name, t_prop_type)); 5253 cleanup: 5254 free(pg_name); 5255 free(prop_name); 5256 free(ev1); 5257 free(actual); 5258 free(t_fmri); 5259 free(t_pg_name); 5260 free(t_pg_type); 5261 free(t_prop_name); 5262 free(t_prop_type); 5263 return (-1); 5264 } 5265 5266 /* 5267 * return 0 on success, -1 on failure. 5268 * set scf_error() to: 5269 * SCF_ERROR_BACKEND_ACCESS 5270 * SCF_ERROR_CONNECTION_BROKEN 5271 * SCF_ERROR_DELETED 5272 * SCF_ERROR_HANDLE_DESTROYED 5273 * SCF_ERROR_INTERNAL 5274 * SCF_ERROR_NO_MEMORY 5275 * SCF_ERROR_NO_RESOURCES 5276 * SCF_ERROR_NOT_BOUND 5277 * SCF_ERROR_PERMISSION_DENIED 5278 * SCF_ERROR_TEMPLATE_INVALID 5279 */ 5280 static int 5281 _add_tmpl_count_error(scf_tmpl_errors_t *errs, scf_tmpl_error_type_t type, 5282 scf_propertygroup_t *pg, const scf_prop_tmpl_t *pt, scf_property_t *prop, 5283 uint64_t count, uint64_t *min, uint64_t *max) 5284 { 5285 char *pg_name = NULL; 5286 char *prop_name = NULL; 5287 char *s_min = NULL; 5288 char *s_max = NULL; 5289 char *num = NULL; 5290 char *t_fmri = NULL; 5291 char *t_pg_name = NULL; 5292 char *t_pg_type = NULL; 5293 char *t_prop_name = NULL; 5294 char *t_prop_type = NULL; 5295 5296 if ((t_fmri = _scf_tmpl_get_fmri(pt->prt_t)) == NULL) 5297 return (-1); 5298 switch (type) { 5299 case SCF_TERR_RANGE_VIOLATION: 5300 case SCF_TERR_CARDINALITY_VIOLATION: 5301 if ((pg_name = _scf_get_pg_name(pg)) == NULL) 5302 goto cleanup; 5303 if ((prop_name = _scf_get_prop_name(prop)) == NULL) 5304 goto cleanup; 5305 break; 5306 case SCF_TERR_VALUE_OUT_OF_RANGE: 5307 /* keep pg_name = NULL and prop_name = NULL */ 5308 break; 5309 } 5310 if (scf_tmpl_pg_name(pt->prt_t, &t_pg_name) == -1) { 5311 goto cleanup; 5312 } 5313 if (scf_tmpl_pg_type(pt->prt_t, &t_pg_type) == -1) { 5314 goto cleanup; 5315 } 5316 if (scf_tmpl_prop_name(pt, &t_prop_name) == -1) { 5317 goto cleanup; 5318 } 5319 t_prop_type = _scf_read_tmpl_prop_type_as_string(pt); 5320 if (t_prop_type != NULL && t_prop_type[0] == '\0') { 5321 free(t_prop_type); 5322 t_prop_type = NULL; 5323 } else if (t_prop_type == NULL) { 5324 goto cleanup; 5325 } 5326 if (t_prop_type == NULL) 5327 if ((t_prop_type = strdup(SCF_TMPL_WILDCARD)) == NULL) { 5328 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 5329 goto cleanup; 5330 } 5331 if (min == NULL) { 5332 if ((s_min = strdup("")) == NULL) { 5333 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 5334 goto cleanup; 5335 } 5336 } else { 5337 if ((s_min = _val_to_string(*min, 0)) == NULL) { 5338 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 5339 goto cleanup; 5340 } 5341 } 5342 if (max == NULL) { 5343 if ((s_max = strdup("")) == NULL) { 5344 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 5345 goto cleanup; 5346 } 5347 } else { 5348 if ((s_max = _val_to_string(*max, 0)) == NULL) { 5349 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 5350 goto cleanup; 5351 } 5352 } 5353 if ((num = _val_to_string(count, 0)) == NULL) { 5354 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 5355 goto cleanup; 5356 } 5357 5358 return (_scf_tmpl_add_error(errs, type, pg_name, prop_name, s_min, 5359 s_max, num, t_fmri, t_pg_name, t_pg_type, t_prop_name, 5360 t_prop_type)); 5361 cleanup: 5362 free(pg_name); 5363 free(prop_name); 5364 free(s_min); 5365 free(s_max); 5366 free(num); 5367 free(t_fmri); 5368 free(t_pg_name); 5369 free(t_pg_type); 5370 free(t_prop_name); 5371 free(t_prop_type); 5372 return (-1); 5373 } 5374 5375 /* 5376 * return 0 on success, -1 on failure. 5377 * set scf_error() to: 5378 * SCF_ERROR_BACKEND_ACCESS 5379 * SCF_ERROR_CONNECTION_BROKEN 5380 * SCF_ERROR_DELETED 5381 * SCF_ERROR_HANDLE_DESTROYED 5382 * SCF_ERROR_INTERNAL 5383 * SCF_ERROR_NO_MEMORY 5384 * SCF_ERROR_NO_RESOURCES 5385 * SCF_ERROR_NOT_BOUND 5386 * SCF_ERROR_PERMISSION_DENIED 5387 * SCF_ERROR_TEMPLATE_INVALID 5388 */ 5389 static int 5390 _add_tmpl_constraint_error(scf_tmpl_errors_t *errs, scf_tmpl_error_type_t type, 5391 scf_propertygroup_t *pg, const scf_prop_tmpl_t *pt, scf_property_t *prop, 5392 scf_value_t *val) 5393 { 5394 scf_type_t val_type; 5395 char *pg_name = NULL; 5396 char *prop_name = NULL; 5397 char *value = NULL; 5398 char *t_fmri = NULL; 5399 char *t_pg_name = NULL; 5400 char *t_pg_type = NULL; 5401 char *t_prop_name = NULL; 5402 char *t_prop_type = NULL; 5403 5404 if ((t_fmri = _scf_tmpl_get_fmri(pt->prt_t)) == NULL) 5405 return (-1); 5406 switch (type) { 5407 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED: 5408 if ((pg_name = _scf_get_pg_name(pg)) == NULL) 5409 goto cleanup; 5410 if ((prop_name = _scf_get_prop_name(prop)) == NULL) 5411 goto cleanup; 5412 /*FALLTHROUGH*/ 5413 case SCF_TERR_INVALID_VALUE: 5414 /* keep pg_name = NULL and prop_name = NULL */ 5415 if ((value = _scf_value_get_as_string(val)) == NULL) 5416 goto cleanup; 5417 break; 5418 case SCF_TERR_PROP_TYPE_MISMATCH: 5419 /* keep pg_name = NULL and prop_name = NULL */ 5420 /* use value for value type */ 5421 val_type = scf_value_type(val); 5422 if ((value = strdup(scf_type_to_string(val_type))) == 5423 NULL) { 5424 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 5425 goto cleanup; 5426 } 5427 break; 5428 } 5429 if (scf_tmpl_pg_name(pt->prt_t, &t_pg_name) == -1) { 5430 goto cleanup; 5431 } 5432 if (scf_tmpl_pg_type(pt->prt_t, &t_pg_type) == -1) { 5433 goto cleanup; 5434 } 5435 if (scf_tmpl_prop_name(pt, &t_prop_name) == -1) { 5436 goto cleanup; 5437 } 5438 t_prop_type = _scf_read_tmpl_prop_type_as_string(pt); 5439 if (t_prop_type != NULL && t_prop_type[0] == '\0') { 5440 free(t_prop_type); 5441 t_prop_type = NULL; 5442 } else if (t_prop_type == NULL) { 5443 goto cleanup; 5444 } 5445 if (t_prop_type == NULL) 5446 if ((t_prop_type = strdup(SCF_TMPL_WILDCARD)) == NULL) { 5447 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 5448 goto cleanup; 5449 } 5450 5451 return (_scf_tmpl_add_error(errs, type, pg_name, prop_name, NULL, NULL, 5452 value, t_fmri, t_pg_name, t_pg_type, t_prop_name, t_prop_type)); 5453 cleanup: 5454 assert(scf_error() != SCF_ERROR_NOT_SET); 5455 free(pg_name); 5456 free(prop_name); 5457 free(value); 5458 free(t_fmri); 5459 free(t_pg_name); 5460 free(t_pg_type); 5461 free(t_prop_name); 5462 free(t_prop_type); 5463 return (-1); 5464 } 5465 5466 /* 5467 * return 0 on success, -1 on failure. 5468 * set scf_error() to: 5469 * SCF_ERROR_BACKEND_ACCESS 5470 * SCF_ERROR_CONNECTION_BROKEN 5471 * SCF_ERROR_DELETED 5472 * SCF_ERROR_HANDLE_DESTROYED 5473 * SCF_ERROR_INTERNAL 5474 * SCF_ERROR_NO_MEMORY 5475 * SCF_ERROR_NO_RESOURCES 5476 * SCF_ERROR_NOT_BOUND 5477 * SCF_ERROR_PERMISSION_DENIED 5478 * SCF_ERROR_TEMPLATE_INVALID 5479 */ 5480 static int 5481 _add_tmpl_int_error(scf_tmpl_errors_t *errs, scf_tmpl_error_type_t type, 5482 scf_propertygroup_t *pg, const scf_prop_tmpl_t *pt, scf_property_t *prop, 5483 int64_t val, int64_t *min, int64_t *max) 5484 { 5485 char *pg_name = NULL; 5486 char *prop_name = NULL; 5487 char *s_min = NULL; 5488 char *s_max = NULL; 5489 char *value = NULL; 5490 char *t_fmri = NULL; 5491 char *t_pg_name = NULL; 5492 char *t_pg_type = NULL; 5493 char *t_prop_name = NULL; 5494 char *t_prop_type = NULL; 5495 5496 if ((t_fmri = _scf_tmpl_get_fmri(pt->prt_t)) == NULL) 5497 return (-1); 5498 5499 switch (type) { 5500 case SCF_TERR_RANGE_VIOLATION: 5501 if ((pg_name = _scf_get_pg_name(pg)) == NULL) 5502 goto cleanup; 5503 if ((prop_name = _scf_get_prop_name(prop)) == NULL) 5504 goto cleanup; 5505 break; 5506 case SCF_TERR_VALUE_OUT_OF_RANGE: 5507 /* keep pg_name = NULL and prop_name = NULL */ 5508 break; 5509 } 5510 if (scf_tmpl_pg_name(pt->prt_t, &t_pg_name) == -1) { 5511 goto cleanup; 5512 } 5513 if (scf_tmpl_pg_type(pt->prt_t, &t_pg_type) == -1) { 5514 goto cleanup; 5515 } 5516 if (scf_tmpl_prop_name(pt, &t_prop_name) == -1) { 5517 goto cleanup; 5518 } 5519 t_prop_type = _scf_read_tmpl_prop_type_as_string(pt); 5520 if (t_prop_type != NULL && t_prop_type[0] == '\0') { 5521 free(t_prop_type); 5522 t_prop_type = NULL; 5523 } else if (t_prop_type == NULL) { 5524 goto cleanup; 5525 } 5526 if (t_prop_type == NULL) 5527 if ((t_prop_type = strdup(SCF_TMPL_WILDCARD)) == NULL) { 5528 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 5529 goto cleanup; 5530 } 5531 if (min == NULL) { 5532 if ((s_min = strdup("")) == NULL) { 5533 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 5534 goto cleanup; 5535 } 5536 } else { 5537 if ((s_min = _val_to_string(*((uint64_t *)min), 1)) == NULL) { 5538 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 5539 goto cleanup; 5540 } 5541 } 5542 if (max == NULL) { 5543 if ((s_max = strdup("")) == NULL) { 5544 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 5545 goto cleanup; 5546 } 5547 } else { 5548 if ((s_max = _val_to_string(*((uint64_t *)max), 1)) == NULL) { 5549 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 5550 goto cleanup; 5551 } 5552 } 5553 if ((value = _val_to_string((uint64_t)val, 1)) == NULL) { 5554 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 5555 goto cleanup; 5556 } 5557 5558 return (_scf_tmpl_add_error(errs, type, pg_name, prop_name, s_min, 5559 s_max, value, t_fmri, t_pg_name, t_pg_type, t_prop_name, 5560 t_prop_type)); 5561 cleanup: 5562 free(pg_name); 5563 free(prop_name); 5564 free(s_min); 5565 free(s_max); 5566 free(value); 5567 free(t_fmri); 5568 free(t_pg_name); 5569 free(t_pg_type); 5570 free(t_prop_name); 5571 free(t_prop_type); 5572 return (-1); 5573 } 5574 5575 /* 5576 * return 0 on success, -1 on failure. 5577 * set scf_error() to: 5578 * SCF_ERROR_BACKEND_ACCESS 5579 * SCF_ERROR_CONNECTION_BROKEN 5580 * SCF_ERROR_DELETED 5581 * SCF_ERROR_HANDLE_DESTROYED 5582 * SCF_ERROR_INTERNAL 5583 * SCF_ERROR_NO_MEMORY 5584 * SCF_ERROR_NO_RESOURCES 5585 * SCF_ERROR_NOT_BOUND 5586 * SCF_ERROR_PERMISSION_DENIED 5587 * SCF_ERROR_TEMPLATE_INVALID 5588 */ 5589 static int 5590 _add_tmpl_pg_redefine_error(scf_tmpl_errors_t *errs, scf_pg_tmpl_t *t, 5591 scf_pg_tmpl_t *r) 5592 { 5593 char *ev1 = NULL; 5594 char *ev2 = NULL; 5595 char *t_fmri = NULL; 5596 char *t_pg_name = NULL; 5597 char *t_pg_type = NULL; 5598 5599 if ((t_fmri = _scf_tmpl_get_fmri(r)) == NULL) 5600 return (-1); 5601 if (scf_tmpl_pg_name(r, &t_pg_name) == -1) { 5602 goto cleanup; 5603 } 5604 if (scf_tmpl_pg_type(r, &t_pg_type) == -1) { 5605 goto cleanup; 5606 } 5607 if (scf_tmpl_pg_name(t, &ev1) == -1) { 5608 goto cleanup; 5609 } 5610 if (scf_tmpl_pg_type(t, &ev2) == -1) { 5611 goto cleanup; 5612 } 5613 5614 return (_scf_tmpl_add_error(errs, SCF_TERR_PG_REDEFINE, NULL, NULL, 5615 ev1, ev2, NULL, t_fmri, t_pg_name, t_pg_type, NULL, NULL)); 5616 cleanup: 5617 free(ev1); 5618 free(ev2); 5619 free(t_fmri); 5620 free(t_pg_name); 5621 free(t_pg_type); 5622 return (-1); 5623 } 5624 5625 /* 5626 * return 0 if value is within count ranges constraint. 5627 * return -1 otherwise 5628 */ 5629 static int 5630 _check_count_ranges(scf_count_ranges_t *cr, uint64_t v) 5631 { 5632 int i; 5633 5634 for (i = 0; i < cr->scr_num_ranges; ++i) { 5635 if (v >= cr->scr_min[i] && 5636 v <= cr->scr_max[i]) { 5637 /* value is within ranges constraint */ 5638 return (0); 5639 } 5640 } 5641 return (-1); 5642 } 5643 5644 /* 5645 * return 0 if value is within count ranges constraint. 5646 * return -1 otherwise 5647 */ 5648 static int 5649 _check_int_ranges(scf_int_ranges_t *ir, int64_t v) 5650 { 5651 int i; 5652 5653 for (i = 0; i < ir->sir_num_ranges; ++i) { 5654 if (v >= ir->sir_min[i] && 5655 v <= ir->sir_max[i]) { 5656 /* value is within integer ranges constraint */ 5657 return (0); 5658 } 5659 } 5660 return (-1); 5661 } 5662 5663 /* 5664 * int _value_in_constraint() 5665 * 5666 * Checks whether the supplied value violates any of the constraints 5667 * specified in the supplied property template. If it does, an appropriate 5668 * error is appended to "errs". pg and prop, if supplied, are used to 5669 * augment the information in the error. Returns 0 on success. 5670 * 5671 * Returns -1 on failure. Sets scf_error(): 5672 * SCF_ERROR_BACKEND_ACCESS 5673 * SCF_ERROR_CONNECTION_BROKEN 5674 * SCF_ERROR_DELETED 5675 * SCF_ERROR_HANDLE_DESTROYED 5676 * SCF_ERROR_INTERNAL 5677 * SCF_ERROR_INVALID_ARGUMENT 5678 * SCF_ERROR_NO_MEMORY 5679 * SCF_ERROR_NO_RESOURCES 5680 * SCF_ERROR_NOT_BOUND 5681 * SCF_ERROR_PERMISSION_DENIED 5682 * SCF_ERROR_TEMPLATE_INVALID 5683 */ 5684 static int 5685 _value_in_constraint(scf_propertygroup_t *pg, scf_property_t *prop, 5686 const scf_prop_tmpl_t *pt, scf_value_t *value, scf_tmpl_errors_t *errs) 5687 { 5688 scf_type_t type, tmpl_type; 5689 scf_values_t vals; 5690 scf_tmpl_error_type_t terr_type; 5691 uint64_t v_count; 5692 int64_t v_int; 5693 char *vstr; 5694 ssize_t sz = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH) + 1; 5695 ssize_t ret = 0; 5696 char **constraints; 5697 int n = 0; 5698 int r; 5699 int err_flag = 0; 5700 scf_count_ranges_t cr; 5701 scf_int_ranges_t ir; 5702 5703 type = scf_value_type(value); 5704 if (type == SCF_TYPE_INVALID) { 5705 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 5706 return (-1); 5707 } 5708 5709 /* Check if template type matches value type. */ 5710 if (scf_tmpl_prop_type(pt, &tmpl_type) == -1) { 5711 if (scf_error() != SCF_ERROR_NOT_FOUND) 5712 /* type is not wildcarded */ 5713 return (-1); 5714 } else if (tmpl_type != type) { 5715 if (errs != NULL) { 5716 if (pg == NULL && prop == NULL) { 5717 if (_add_tmpl_constraint_error(errs, 5718 SCF_TERR_PROP_TYPE_MISMATCH, NULL, pt, 5719 NULL, value) == -1) 5720 return (-1); 5721 } 5722 } 5723 return (1); 5724 } 5725 5726 /* Numeric values should be checked against any range constraints. */ 5727 switch (type) { 5728 case SCF_TYPE_COUNT: 5729 r = scf_value_get_count(value, &v_count); 5730 assert(r == 0); 5731 5732 if (scf_tmpl_value_count_range_constraints(pt, &cr) != 0) { 5733 if (scf_error() == SCF_ERROR_NOT_FOUND) 5734 break; 5735 if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) 5736 (void) scf_set_error( 5737 SCF_ERROR_TEMPLATE_INVALID); 5738 return (-1); 5739 } else { 5740 if (_check_count_ranges(&cr, v_count) == 0) { 5741 /* value is within ranges constraint */ 5742 scf_count_ranges_destroy(&cr); 5743 return (0); 5744 } 5745 scf_count_ranges_destroy(&cr); 5746 } 5747 5748 /* 5749 * If we get here, we have a possible constraint 5750 * violation. 5751 */ 5752 err_flag |= 0x1; /* RANGE_VIOLATION, count */ 5753 break; 5754 case SCF_TYPE_INTEGER: 5755 if (scf_value_get_integer(value, &v_int) != 0) 5756 assert(0); 5757 if (scf_tmpl_value_int_range_constraints(pt, &ir) != 0) { 5758 if (scf_error() == SCF_ERROR_NOT_FOUND) 5759 break; 5760 if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED) 5761 (void) scf_set_error( 5762 SCF_ERROR_TEMPLATE_INVALID); 5763 return (-1); 5764 } else { 5765 if (_check_int_ranges(&ir, v_int) == 0) { 5766 /* value is within ranges constraint */ 5767 scf_int_ranges_destroy(&ir); 5768 return (0); 5769 } 5770 scf_int_ranges_destroy(&ir); 5771 } 5772 /* 5773 * If we get here, we have a possible constraint 5774 * violation. 5775 */ 5776 err_flag |= 0x2; /* RANGE_VIOLATION, integer */ 5777 break; 5778 default: 5779 break; 5780 } 5781 5782 vstr = malloc(sz); 5783 if (vstr == NULL) { 5784 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 5785 return (-1); 5786 } 5787 5788 /* 5789 * If a set of names is provided, confirm value has one of 5790 * those names. 5791 */ 5792 if (scf_tmpl_value_name_constraints(pt, &vals) != 0) { 5793 free(vstr); 5794 if (scf_error() != SCF_ERROR_NOT_FOUND) { 5795 return (-1); 5796 } 5797 } else { 5798 r = scf_value_get_as_string_typed(value, type, vstr, sz); 5799 5800 /* 5801 * All errors (INVALID_ARGUMENT, NOT_SET, TYPE_MISMATCH) 5802 * should be impossible or already caught above. 5803 */ 5804 assert(r > 0); 5805 5806 constraints = vals.values.v_astring; 5807 for (n = 0; constraints[n] != NULL; ++n) { 5808 if (strcmp(constraints[n], vstr) == 0) { 5809 /* value is within constraint */ 5810 scf_values_destroy(&vals); 5811 free(vstr); 5812 return (0); 5813 } 5814 } 5815 /* if we get here, we have a constraint violation */ 5816 err_flag |= 0x4; /* CONSTRAINT_VIOLATED */ 5817 scf_values_destroy(&vals); 5818 free(vstr); 5819 } 5820 if (err_flag != 0) 5821 ret = 1; 5822 /* register the errors found */ 5823 if (ret == 1 && errs != NULL) { 5824 if ((err_flag & 0x1) == 0x1) { 5825 /* 5826 * Help make the error more human-friendly. If 5827 * pg and prop are provided, we know we're 5828 * validating repository data. If they're not, 5829 * we're validating a potentially hypothetical 5830 * value. 5831 */ 5832 if (pg == NULL && prop == NULL) 5833 terr_type = SCF_TERR_VALUE_OUT_OF_RANGE; 5834 else 5835 terr_type = SCF_TERR_RANGE_VIOLATION; 5836 if (_add_tmpl_count_error(errs, terr_type, pg, pt, 5837 prop, v_count, 0, 0) == -1) 5838 ret = -1; 5839 } 5840 if ((err_flag & 0x2) == 0x2) { 5841 if (pg == NULL && prop == NULL) 5842 terr_type = SCF_TERR_VALUE_OUT_OF_RANGE; 5843 else 5844 terr_type = SCF_TERR_RANGE_VIOLATION; 5845 if (_add_tmpl_int_error(errs, terr_type, pg, pt, prop, 5846 v_int, 0, 0) == -1) 5847 ret = -1; 5848 } 5849 if ((err_flag & 0x4) == 0x4) { 5850 if (pg == NULL && prop == NULL) 5851 terr_type = SCF_TERR_INVALID_VALUE; 5852 else 5853 terr_type = SCF_TERR_VALUE_CONSTRAINT_VIOLATED; 5854 if (_add_tmpl_constraint_error(errs, terr_type, pg, 5855 pt, prop, value) == -1) 5856 ret = -1; 5857 } 5858 } 5859 return (ret); 5860 } 5861 5862 /* 5863 * Returns -1 on failure. Sets scf_error(): 5864 * SCF_ERROR_BACKEND_ACCESS 5865 * SCF_ERROR_CONNECTION_BROKEN 5866 * SCF_ERROR_DELETED 5867 * SCF_ERROR_HANDLE_DESTROYED 5868 * SCF_ERROR_INTERNAL 5869 * SCF_ERROR_INVALID_ARGUMENT 5870 * SCF_ERROR_NO_MEMORY 5871 * SCF_ERROR_NO_RESOURCES 5872 * SCF_ERROR_NOT_BOUND 5873 * SCF_ERROR_PERMISSION_DENIED 5874 * SCF_ERROR_TEMPLATE_INVALID 5875 */ 5876 int 5877 scf_tmpl_value_in_constraint(const scf_prop_tmpl_t *pt, scf_value_t *value, 5878 scf_tmpl_errors_t **errs) 5879 { 5880 scf_tmpl_errors_t *e = NULL; 5881 5882 if (errs != NULL) { 5883 char *fmri; 5884 5885 if ((fmri = _scf_tmpl_get_fmri(pt->prt_t)) == NULL) 5886 return (-1); 5887 *errs = _scf_create_errors(fmri, 1); 5888 free(fmri); 5889 if (*errs == NULL) 5890 return (-1); 5891 e = *errs; 5892 } 5893 5894 return (_value_in_constraint(NULL, NULL, pt, value, e)); 5895 } 5896 5897 scf_tmpl_error_t * 5898 scf_tmpl_next_error(scf_tmpl_errors_t *errs) 5899 { 5900 if (errs->tes_index < errs->tes_num_errs) { 5901 assert(errs->tes_errs[errs->tes_index] != NULL); 5902 return (errs->tes_errs[errs->tes_index++]); 5903 } else { 5904 return (NULL); 5905 } 5906 } 5907 5908 void 5909 scf_tmpl_reset_errors(scf_tmpl_errors_t *errs) 5910 { 5911 errs->tes_index = 0; 5912 } 5913 5914 int 5915 scf_tmpl_strerror(scf_tmpl_error_t *err, char *s, size_t n, int flag) 5916 { 5917 const char *str; 5918 int i; 5919 int ret = -1; 5920 int nsz = 0; /* err msg length */ 5921 int sz = n; /* available buffer size */ 5922 char *buf = s; /* where to append in buffer */ 5923 char *s0 = (flag == SCF_TMPL_STRERROR_HUMAN) ? ":\n\t" : ": "; 5924 char *s1 = (flag == SCF_TMPL_STRERROR_HUMAN) ? "\n\t" : "; "; 5925 char *sep = s0; 5926 const char *val; 5927 5928 /* prefix */ 5929 if (err->te_errs->tes_prefix != NULL) { 5930 ret = snprintf(buf, sz, "%s", dgettext(TEXT_DOMAIN, 5931 err->te_errs->tes_prefix)); 5932 nsz += ret; 5933 sz = (sz - ret) > 0 ? sz - ret : 0; 5934 buf = (sz > 0) ? s + nsz : NULL; 5935 } 5936 /* error message */ 5937 ret = snprintf(buf, sz, "%s", dgettext(TEXT_DOMAIN, 5938 em_desc[err->te_type].em_msg)); 5939 nsz += ret; 5940 sz = (sz - ret) > 0 ? sz - ret : 0; 5941 buf = (sz > 0) ? s + nsz : NULL; 5942 5943 for (i = 0; _tmpl_error_items[i].get_desc != NULL; ++i) { 5944 if ((str = _tmpl_error_items[i].get_desc(err)) == NULL) 5945 /* no item to print */ 5946 continue; 5947 val = _tmpl_error_items[i].get_val(err); 5948 ret = snprintf(buf, sz, "%s%s=\"%s\"", sep, str, 5949 (val == NULL) ? "" : val); 5950 nsz += ret; 5951 sz = (sz - ret) > 0 ? sz - ret : 0; 5952 buf = (sz > 0) ? s + nsz : NULL; 5953 sep = s1; 5954 } 5955 return (nsz); 5956 } 5957 5958 /* 5959 * return 0 on success, -1 on failure. 5960 * set scf_error() to: 5961 * SCF_ERROR_BACKEND_ACCESS 5962 * SCF_ERROR_CONNECTION_BROKEN 5963 * SCF_ERROR_DELETED 5964 * SCF_ERROR_HANDLE_DESTROYED 5965 * SCF_ERROR_INTERNAL 5966 * SCF_ERROR_NO_MEMORY 5967 * SCF_ERROR_NO_RESOURCES 5968 * SCF_ERROR_NOT_BOUND 5969 * SCF_ERROR_PERMISSION_DENIED 5970 * SCF_ERROR_TEMPLATE_INVALID 5971 */ 5972 static int 5973 _validate_cardinality(scf_propertygroup_t *pg, scf_prop_tmpl_t *pt, 5974 scf_property_t *prop, scf_tmpl_errors_t *errs) 5975 { 5976 uint64_t min, max; 5977 scf_handle_t *h; 5978 scf_iter_t *iter = NULL; 5979 scf_value_t *val = NULL; 5980 int count = 0; 5981 int ret = -1; 5982 int r; 5983 5984 if (scf_tmpl_prop_cardinality(pt, &min, &max) != 0) { 5985 if (scf_error() == SCF_ERROR_NOT_FOUND) 5986 return (0); 5987 else 5988 return (-1); 5989 } 5990 5991 /* Any number of values permitted. Just return success. */ 5992 if (min == 0 && max == UINT64_MAX) { 5993 return (0); 5994 } 5995 5996 h = scf_property_handle(prop); 5997 if (h == NULL) { 5998 assert(scf_error() == SCF_ERROR_HANDLE_DESTROYED); 5999 goto cleanup; 6000 } 6001 6002 iter = scf_iter_create(h); 6003 val = scf_value_create(h); 6004 if (iter == NULL || val == NULL) { 6005 if (ismember(scf_error(), errors_server)) { 6006 goto cleanup; 6007 } else { 6008 assert(0); 6009 abort(); 6010 } 6011 } 6012 6013 if (scf_iter_property_values(iter, prop) != 0) { 6014 if (ismember(scf_error(), errors_server)) { 6015 goto cleanup; 6016 } else { 6017 assert(0); 6018 abort(); 6019 } 6020 } 6021 6022 while ((r = scf_iter_next_value(iter, val)) == 1) 6023 count++; 6024 6025 if (r < 0) { 6026 if (ismember(scf_error(), errors_server)) { 6027 goto cleanup; 6028 } else { 6029 assert(0); 6030 abort(); 6031 } 6032 } 6033 6034 if (count < min || count > max) 6035 if (_add_tmpl_count_error(errs, SCF_TERR_CARDINALITY_VIOLATION, 6036 pg, pt, prop, (uint64_t)count, &min, &max) == -1) 6037 goto cleanup; 6038 6039 ret = 0; 6040 6041 cleanup: 6042 scf_iter_destroy(iter); 6043 scf_value_destroy(val); 6044 return (ret); 6045 } 6046 6047 /* 6048 * Returns -1 on error. Sets scf_error(): 6049 * SCF_ERROR_BACKEND_ACCESS 6050 * SCF_ERROR_CONNECTION_BROKEN 6051 * SCF_ERROR_DELETED 6052 * SCF_ERROR_HANDLE_DESTROYED 6053 * SCF_ERROR_INTERNAL 6054 * SCF_ERROR_NO_MEMORY 6055 * SCF_ERROR_NO_RESOURCES 6056 * SCF_ERROR_NOT_BOUND 6057 * SCF_ERROR_PERMISSION_DENIED 6058 * SCF_ERROR_TEMPLATE_INVALID 6059 */ 6060 static int 6061 _check_property(scf_prop_tmpl_t *pt, scf_propertygroup_t *pg, 6062 scf_property_t *prop, scf_tmpl_errors_t *errs) 6063 { 6064 scf_type_t tmpl_type; 6065 uint8_t required; 6066 scf_handle_t *h; 6067 scf_iter_t *iter = NULL; 6068 scf_value_t *val = NULL; 6069 int r; 6070 int ret = -1; 6071 6072 h = scf_pg_handle(pg); 6073 if (h == NULL) { 6074 assert(scf_error() == SCF_ERROR_HANDLE_DESTROYED); 6075 return (-1); 6076 } 6077 6078 iter = scf_iter_create(h); 6079 val = scf_value_create(h); 6080 if (iter == NULL || val == NULL) { 6081 if (ismember(scf_error(), errors_server)) { 6082 scf_iter_destroy(iter); 6083 scf_value_destroy(val); 6084 return (-1); 6085 } else { 6086 assert(0); 6087 abort(); 6088 } 6089 } 6090 6091 if (scf_tmpl_prop_required(pt, &required) != 0) 6092 goto cleanup; 6093 6094 /* Check type */ 6095 if (scf_tmpl_prop_type(pt, &tmpl_type) == -1) { 6096 if (scf_error() != SCF_ERROR_NOT_FOUND) { 6097 goto cleanup; 6098 } else if (required) { 6099 /* If required, type must be specified. */ 6100 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID); 6101 goto cleanup; 6102 } 6103 } else if (scf_property_is_type(prop, tmpl_type) != 0) { 6104 if (ismember(scf_error(), errors_server)) { 6105 goto cleanup; 6106 } else switch (scf_error()) { 6107 case SCF_ERROR_TYPE_MISMATCH: 6108 if (_add_tmpl_wrong_prop_type_error(errs, pg, pt, 6109 prop) == -1) 6110 goto cleanup; 6111 break; 6112 6113 case SCF_ERROR_INVALID_ARGUMENT: 6114 /* 6115 * tmpl_prop_type shouldn't have handed back 6116 * an invalid property type. 6117 */ 6118 case SCF_ERROR_NOT_SET: 6119 default: 6120 assert(0); 6121 abort(); 6122 } 6123 } 6124 6125 6126 /* Cardinality */ 6127 if (_validate_cardinality(pg, pt, prop, errs) == -1) 6128 goto cleanup; 6129 6130 /* Value constraints */ 6131 /* 6132 * Iterate through each value, and confirm it is defined as 6133 * constrained. 6134 */ 6135 if (scf_iter_property_values(iter, prop) != 0) { 6136 assert(scf_error() != SCF_ERROR_NOT_SET && 6137 scf_error() != SCF_ERROR_HANDLE_MISMATCH); 6138 goto cleanup; 6139 } 6140 6141 while ((r = scf_iter_next_value(iter, val)) == 1) { 6142 if (_value_in_constraint(pg, prop, pt, val, errs) == -1) { 6143 if (ismember(scf_error(), errors_server)) { 6144 goto cleanup; 6145 } else switch (scf_error()) { 6146 case SCF_ERROR_TEMPLATE_INVALID: 6147 goto cleanup; 6148 6149 case SCF_ERROR_INVALID_ARGUMENT: 6150 default: 6151 assert(0); 6152 abort(); 6153 } 6154 } 6155 } 6156 6157 if (r < 0) { 6158 if (ismember(scf_error(), errors_server)) { 6159 goto cleanup; 6160 } else { 6161 assert(0); 6162 abort(); 6163 } 6164 } 6165 6166 ret = 0; 6167 6168 cleanup: 6169 scf_iter_destroy(iter); 6170 scf_value_destroy(val); 6171 return (ret); 6172 } 6173 6174 /* 6175 * Returns -1 on failure, sets scf_error() to: 6176 * SCF_ERROR_BACKEND_ACCESS 6177 * SCF_ERROR_CONNECTION_BROKEN 6178 * SCF_ERROR_DELETED 6179 * SCF_ERROR_HANDLE_DESTROYED 6180 * SCF_ERROR_INTERNAL 6181 * SCF_ERROR_NO_MEMORY 6182 * SCF_ERROR_NO_RESOURCES 6183 * SCF_ERROR_NOT_BOUND 6184 * SCF_ERROR_PERMISSION_DENIED 6185 * SCF_ERROR_TEMPLATE_INVALID 6186 */ 6187 static int 6188 _check_pg(scf_pg_tmpl_t *t, scf_propertygroup_t *pg, char *pg_name, 6189 char *type, scf_tmpl_errors_t *errs) 6190 { 6191 scf_prop_tmpl_t *pt = NULL; 6192 char *pg_type = NULL; 6193 scf_iter_t *iter = NULL; 6194 uint8_t pg_required; 6195 scf_property_t *prop = NULL; 6196 scf_handle_t *h; 6197 int r; 6198 char *prop_name = NULL; 6199 ssize_t nsize = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1; 6200 int ret = -1; 6201 6202 assert(pg_name != NULL); 6203 assert(t != NULL); 6204 assert(pg != NULL); 6205 assert(type != NULL); 6206 assert(nsize != 0); 6207 6208 if ((h = scf_pg_handle(pg)) == NULL) { 6209 assert(scf_error() == SCF_ERROR_HANDLE_DESTROYED); 6210 return (-1); 6211 } 6212 if ((pt = scf_tmpl_prop_create(h)) == NULL) { 6213 assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT); 6214 return (-1); 6215 } 6216 6217 if ((prop = scf_property_create(h)) == NULL) { 6218 assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT); 6219 goto cleanup; 6220 } 6221 6222 if ((iter = scf_iter_create(h)) == NULL) { 6223 assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT); 6224 goto cleanup; 6225 } 6226 if ((prop_name = malloc(nsize)) == NULL) { 6227 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 6228 goto cleanup; 6229 } 6230 6231 if (scf_tmpl_pg_required(t, &pg_required) != 0) 6232 goto cleanup; 6233 6234 if (scf_tmpl_pg_type(t, &pg_type) == -1) { 6235 goto cleanup; 6236 } else if (pg_required != 0 && 6237 strcmp(SCF_TMPL_WILDCARD, pg_type) == 0) { 6238 /* Type must be specified for required pgs. */ 6239 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID); 6240 goto cleanup; 6241 } 6242 6243 if (pg_type != NULL) { 6244 if (strcmp(pg_type, type) != 0 && 6245 strcmp(pg_type, SCF_TMPL_WILDCARD) != 0) { 6246 if (_add_tmpl_wrong_pg_type_error(errs, t, pg) == -1) 6247 goto cleanup; 6248 } 6249 } 6250 6251 6252 /* Iterate through properties in the repository and check them. */ 6253 if (scf_iter_pg_properties(iter, pg) != 0) { 6254 if (ismember(scf_error(), errors_server)) { 6255 goto cleanup; 6256 } else { 6257 assert(0); 6258 abort(); 6259 } 6260 } 6261 6262 while ((r = scf_iter_next_property(iter, prop)) == 1) { 6263 if (scf_property_get_name(prop, prop_name, nsize) == -1) { 6264 assert(scf_error() != SCF_ERROR_NOT_SET); 6265 goto cleanup; 6266 } 6267 if (scf_tmpl_get_by_prop(t, prop_name, pt, 0) != 0) { 6268 if (ismember(scf_error(), errors_server)) { 6269 goto cleanup; 6270 } else switch (scf_error()) { 6271 case SCF_ERROR_NOT_FOUND: 6272 /* No template. Continue. */ 6273 continue; 6274 6275 case SCF_ERROR_INVALID_ARGUMENT: 6276 default: 6277 assert(0); 6278 abort(); 6279 } 6280 } 6281 6282 if (_check_property(pt, pg, prop, errs) != 0) 6283 goto cleanup; 6284 } 6285 6286 if (r < 0) { 6287 if (ismember(scf_error(), errors_server)) { 6288 goto cleanup; 6289 } else { 6290 assert(0); 6291 abort(); 6292 } 6293 } 6294 6295 scf_tmpl_prop_reset(pt); 6296 free(prop_name); 6297 prop_name = NULL; 6298 /* 6299 * Confirm required properties are present. 6300 */ 6301 while ((r = scf_tmpl_iter_props(t, pt, 6302 SCF_PROP_TMPL_FLAG_REQUIRED)) == 0) { 6303 scf_type_t prop_type; 6304 6305 if (scf_tmpl_prop_name(pt, &prop_name) == -1) 6306 goto cleanup; 6307 6308 /* required properties cannot have type wildcarded */ 6309 if (scf_tmpl_prop_type(pt, &prop_type) == -1) { 6310 if (scf_error() == SCF_ERROR_NOT_FOUND) 6311 (void) scf_set_error( 6312 SCF_ERROR_TEMPLATE_INVALID); 6313 goto cleanup; 6314 } 6315 6316 if (scf_pg_get_property(pg, prop_name, prop) != 0) { 6317 if (ismember(scf_error(), errors_server)) { 6318 goto cleanup; 6319 } else switch (scf_error()) { 6320 case SCF_ERROR_NOT_FOUND: 6321 if (_add_tmpl_missing_prop_error(errs, t, pg, 6322 pt) == -1) 6323 goto cleanup; 6324 break; 6325 6326 case SCF_ERROR_INVALID_ARGUMENT: 6327 (void) scf_set_error( 6328 SCF_ERROR_TEMPLATE_INVALID); 6329 goto cleanup; 6330 6331 case SCF_ERROR_HANDLE_MISMATCH: 6332 case SCF_ERROR_NOT_SET: 6333 default: 6334 assert(0); 6335 abort(); 6336 } 6337 } 6338 free(prop_name); 6339 prop_name = NULL; 6340 } 6341 if (r < 0) { 6342 if (ismember(scf_error(), errors_server)) { 6343 goto cleanup; 6344 } else switch (scf_error()) { 6345 case SCF_ERROR_NOT_FOUND: 6346 break; 6347 6348 case SCF_ERROR_TEMPLATE_INVALID: 6349 goto cleanup; 6350 6351 case SCF_ERROR_INVALID_ARGUMENT: 6352 default: 6353 assert(0); 6354 abort(); 6355 } 6356 } 6357 6358 ret = 0; 6359 cleanup: 6360 scf_tmpl_prop_destroy(pt); 6361 scf_iter_destroy(iter); 6362 scf_property_destroy(prop); 6363 free(prop_name); 6364 free(pg_type); 6365 return (ret); 6366 } 6367 6368 /* 6369 * Checks if instance fmri redefines any pgs defined in restarter or global 6370 * Return -1 on failure, sets scf_error() to: 6371 * SCF_ERROR_BACKEND_ACCESS 6372 * SCF_ERROR_CONNECTION_BROKEN 6373 * SCF_ERROR_DELETED 6374 * SCF_ERROR_HANDLE_DESTROYED 6375 * SCF_ERROR_INTERNAL 6376 * SCF_ERROR_INVALID_ARGUMENT 6377 * SCF_ERROR_NO_MEMORY 6378 * SCF_ERROR_NO_RESOURCES 6379 * SCF_ERROR_NOT_BOUND 6380 * SCF_ERROR_NOT_FOUND 6381 * SCF_ERROR_PERMISSION_DENIED 6382 * SCF_ERROR_TEMPLATE_INVALID 6383 */ 6384 static int 6385 _scf_tmpl_check_pg_redef(scf_handle_t *h, const char *fmri, 6386 const char *snapname, scf_tmpl_errors_t *errs) 6387 { 6388 scf_pg_tmpl_t *t = NULL; 6389 scf_pg_tmpl_t *r = NULL; 6390 char *pg_name = NULL; 6391 char *pg_name_r = NULL; 6392 char *pg_type = NULL; 6393 char *pg_type_r = NULL; 6394 char *target = NULL; 6395 int ret_val = -1; 6396 int ret; 6397 6398 t = scf_tmpl_pg_create(h); 6399 r = scf_tmpl_pg_create(h); 6400 if (t == NULL || r == NULL) 6401 goto cleanup; 6402 6403 while ((ret = scf_tmpl_iter_pgs(t, fmri, snapname, NULL, 6404 SCF_PG_TMPL_FLAG_EXACT)) == 1) { 6405 if (scf_tmpl_pg_name(t, &pg_name) == -1) { 6406 goto cleanup; 6407 } 6408 if (scf_tmpl_pg_type(t, &pg_type) == -1) { 6409 goto cleanup; 6410 } 6411 /* look for a redefinition of a global/restarter pg_pattern */ 6412 while ((ret = scf_tmpl_iter_pgs(r, fmri, snapname, pg_type, 6413 0)) == 1) { 6414 if (scf_tmpl_pg_name(r, &pg_name_r) == -1) { 6415 goto cleanup; 6416 } else if (strcmp(pg_name_r, SCF_TMPL_WILDCARD) != 0 && 6417 strcmp(pg_name, SCF_TMPL_WILDCARD) != 0 && 6418 strcmp(pg_name, pg_name_r) != 0) { 6419 /* not a match */ 6420 free(pg_name_r); 6421 pg_name_r = NULL; 6422 continue; 6423 } 6424 if (scf_tmpl_pg_type(r, &pg_type_r) == -1) { 6425 goto cleanup; 6426 } else if (strcmp(pg_type_r, SCF_TMPL_WILDCARD) != 0 && 6427 strcmp(pg_type, SCF_TMPL_WILDCARD) != 0 && 6428 strcmp(pg_type, pg_type_r) != 0) { 6429 /* not a match */ 6430 free(pg_name_r); 6431 pg_name_r = NULL; 6432 free(pg_type_r); 6433 pg_type_r = NULL; 6434 continue; 6435 } 6436 if (scf_tmpl_pg_target(r, &target) == -1) { 6437 target = NULL; 6438 goto cleanup; 6439 } 6440 if (strcmp(target, SCF_TM_TARGET_ALL) == 0 || 6441 strcmp(target, SCF_TM_TARGET_DELEGATE) == 0) { 6442 /* found a pg_pattern redefinition */ 6443 if (_add_tmpl_pg_redefine_error(errs, t, 6444 r) == -1) 6445 goto cleanup; 6446 free(pg_name_r); 6447 pg_name_r = NULL; 6448 free(pg_type_r); 6449 pg_type_r = NULL; 6450 free(target); 6451 target = NULL; 6452 break; 6453 } 6454 free(pg_name_r); 6455 pg_name_r = NULL; 6456 free(pg_type_r); 6457 pg_type_r = NULL; 6458 free(target); 6459 target = NULL; 6460 } 6461 if (ret == -1) 6462 goto cleanup; 6463 scf_tmpl_pg_reset(r); 6464 6465 free(pg_name); 6466 free(pg_type); 6467 pg_name = NULL; 6468 pg_type = NULL; 6469 } 6470 if (ret == -1) 6471 goto cleanup; 6472 6473 ret_val = 0; 6474 6475 cleanup: 6476 scf_tmpl_pg_destroy(t); 6477 scf_tmpl_pg_destroy(r); 6478 free(pg_name); 6479 free(pg_type); 6480 free(pg_name_r); 6481 free(pg_type_r); 6482 free(target); 6483 6484 if (ret_val == -1) { 6485 if (!ismember(scf_error(), errors_server)) { 6486 switch (scf_error()) { 6487 case SCF_ERROR_TYPE_MISMATCH: 6488 (void) scf_set_error( 6489 SCF_ERROR_TEMPLATE_INVALID); 6490 /*FALLTHROUGH*/ 6491 6492 case SCF_ERROR_CONSTRAINT_VIOLATED: 6493 case SCF_ERROR_INVALID_ARGUMENT: 6494 case SCF_ERROR_NOT_FOUND: 6495 case SCF_ERROR_TEMPLATE_INVALID: 6496 break; 6497 6498 case SCF_ERROR_HANDLE_MISMATCH: 6499 case SCF_ERROR_NOT_SET: 6500 default: 6501 assert(0); 6502 abort(); 6503 } 6504 } 6505 } 6506 return (ret_val); 6507 } 6508 6509 /* 6510 * Returns -1 on failure, sets scf_error() to: 6511 * SCF_ERROR_BACKEND_ACCESS 6512 * SCF_ERROR_CONNECTION_BROKEN 6513 * SCF_ERROR_DELETED 6514 * SCF_ERROR_HANDLE_DESTROYED 6515 * SCF_ERROR_INTERNAL 6516 * SCF_ERROR_INVALID_ARGUMENT 6517 * SCF_ERROR_NO_MEMORY 6518 * SCF_ERROR_NO_RESOURCES 6519 * SCF_ERROR_NOT_BOUND 6520 * SCF_ERROR_NOT_FOUND 6521 * SCF_ERROR_PERMISSION_DENIED 6522 * SCF_ERROR_TEMPLATE_INVALID 6523 */ 6524 int 6525 scf_tmpl_validate_fmri(scf_handle_t *h, const char *fmri, const char *snapshot, 6526 scf_tmpl_errors_t **errs, int flags) 6527 { 6528 scf_pg_tmpl_t *t = NULL; 6529 scf_iter_t *iter = NULL; 6530 scf_propertygroup_t *pg = NULL; 6531 scf_instance_t *inst = NULL; 6532 scf_snapshot_t *snap = NULL; 6533 char *type = NULL; 6534 char *pg_name = NULL; 6535 ssize_t rsize = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH) + 1; 6536 ssize_t nsize = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1; 6537 int ret = -1; 6538 int r; 6539 6540 assert(errs != NULL); 6541 6542 if ((*errs = _scf_create_errors(fmri, 1)) == NULL) 6543 return (-1); 6544 6545 if ((pg = scf_pg_create(h)) == NULL || 6546 (iter = scf_iter_create(h)) == NULL || 6547 (inst = scf_instance_create(h)) == NULL || 6548 (t = scf_tmpl_pg_create(h)) == NULL) { 6549 /* 6550 * Sets SCF_ERROR_INVALID_ARGUMENT, SCF_ERROR_NO_MEMORY, 6551 * SCF_ERROR_NO_RESOURCES, SCF_ERROR_INTERNAL or 6552 * SCF_ERROR_HANDLE_DESTROYED. 6553 */ 6554 goto cleanup; 6555 } 6556 6557 if ((type = malloc(rsize)) == NULL || 6558 (pg_name = malloc(nsize)) == NULL) { 6559 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 6560 goto cleanup; 6561 } 6562 6563 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL, NULL, 6564 SCF_DECODE_FMRI_EXACT|SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) { 6565 if (ismember(scf_error(), errors_server)) { 6566 goto cleanup; 6567 } else switch (scf_error()) { 6568 case SCF_ERROR_CONSTRAINT_VIOLATED: 6569 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID); 6570 /*FALLTHROUGH*/ 6571 6572 case SCF_ERROR_INVALID_ARGUMENT: 6573 case SCF_ERROR_NOT_FOUND: 6574 goto cleanup; 6575 6576 case SCF_ERROR_HANDLE_MISMATCH: 6577 case SCF_ERROR_NOT_SET: 6578 default: 6579 assert(0); 6580 abort(); 6581 } 6582 } 6583 6584 if (snapshot == NULL || strcmp(snapshot, "running") == 0 || 6585 (flags & SCF_TMPL_VALIDATE_FLAG_CURRENT)) { 6586 if (_get_snapshot(inst, NULL, &snap) == -1) 6587 goto cleanup; 6588 } else { 6589 (void) scf_set_error(SCF_ERROR_NONE); 6590 if (_get_snapshot(inst, snapshot, &snap) == -1) { 6591 goto cleanup; 6592 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 6593 goto cleanup; 6594 } 6595 } 6596 if (_scf_tmpl_check_pg_redef(h, fmri, snapshot, *errs) != 0) { 6597 goto cleanup; 6598 } 6599 6600 /* 6601 * Check that property groups on this instance conform to the template. 6602 */ 6603 if (scf_iter_instance_pgs_composed(iter, inst, snap) != 0) { 6604 if (ismember(scf_error(), errors_server)) { 6605 goto cleanup; 6606 } else { 6607 assert(0); 6608 abort(); 6609 } 6610 } 6611 6612 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 6613 if (scf_pg_get_name(pg, pg_name, nsize) == -1) { 6614 if (ismember(scf_error(), errors_server)) { 6615 goto cleanup; 6616 } else { 6617 assert(0); 6618 abort(); 6619 } 6620 } 6621 6622 if (scf_pg_get_type(pg, type, rsize) == -1) { 6623 if (ismember(scf_error(), errors_server)) { 6624 goto cleanup; 6625 } else { 6626 assert(0); 6627 abort(); 6628 } 6629 } 6630 6631 if (scf_tmpl_get_by_pg_name(fmri, snapshot, pg_name, type, t, 6632 0) != 0) { 6633 if (ismember(scf_error(), errors_server)) { 6634 goto cleanup; 6635 } else switch (scf_error()) { 6636 case SCF_ERROR_NOT_FOUND: 6637 continue; 6638 6639 case SCF_ERROR_INVALID_ARGUMENT: 6640 goto cleanup; 6641 6642 default: 6643 assert(0); 6644 abort(); 6645 } 6646 } 6647 6648 if (_check_pg(t, pg, pg_name, type, *errs) != 0) 6649 goto cleanup; 6650 } 6651 if (r < 0) { 6652 if (ismember(scf_error(), errors_server)) { 6653 goto cleanup; 6654 } else { 6655 assert(0); 6656 abort(); 6657 } 6658 } 6659 6660 scf_tmpl_pg_reset(t); 6661 6662 /* 6663 * Confirm required property groups are present. 6664 */ 6665 while ((r = scf_tmpl_iter_pgs(t, fmri, snapshot, NULL, 6666 SCF_PG_TMPL_FLAG_REQUIRED)) == 1) { 6667 free(pg_name); 6668 free(type); 6669 6670 if (scf_tmpl_pg_name(t, &pg_name) == -1) 6671 goto cleanup; 6672 if (scf_tmpl_pg_type(t, &type) == -1) 6673 goto cleanup; 6674 /* 6675 * required property group templates should not have 6676 * wildcarded name or type 6677 */ 6678 if (strcmp(pg_name, SCF_TMPL_WILDCARD) == 0 || 6679 strcmp(type, SCF_TMPL_WILDCARD) == 0) { 6680 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID); 6681 goto cleanup; 6682 } 6683 6684 if (_get_pg(NULL, inst, snap, pg_name, pg) != 0) { 6685 if (ismember(scf_error(), errors_server)) { 6686 goto cleanup; 6687 } else switch (scf_error()) { 6688 case SCF_ERROR_NOT_FOUND: 6689 if (_add_tmpl_missing_pg_error(*errs, t) == -1) 6690 goto cleanup; 6691 continue; 6692 6693 case SCF_ERROR_INVALID_ARGUMENT: 6694 case SCF_ERROR_HANDLE_MISMATCH: 6695 case SCF_ERROR_NOT_SET: 6696 default: 6697 assert(0); 6698 abort(); 6699 } 6700 } 6701 } 6702 if (r < 0) { 6703 if (ismember(scf_error(), errors_server)) { 6704 goto cleanup; 6705 } else switch (scf_error()) { 6706 case SCF_ERROR_NOT_FOUND: 6707 break; 6708 6709 case SCF_ERROR_INVALID_ARGUMENT: 6710 goto cleanup; 6711 6712 default: 6713 assert(0); 6714 abort(); 6715 } 6716 } 6717 6718 ret = 0; 6719 if ((*errs)->tes_num_errs > 0) 6720 ret = 1; 6721 cleanup: 6722 if (ret != 1) { 6723 /* there are no errors to report */ 6724 scf_tmpl_errors_destroy(*errs); 6725 *errs = NULL; 6726 } 6727 scf_tmpl_pg_destroy(t); 6728 free(type); 6729 free(pg_name); 6730 6731 scf_iter_destroy(iter); 6732 scf_pg_destroy(pg); 6733 scf_instance_destroy(inst); 6734 scf_snapshot_destroy(snap); 6735 6736 return (ret); 6737 } 6738 6739 void 6740 scf_tmpl_errors_destroy(scf_tmpl_errors_t *errs) 6741 { 6742 int i; 6743 scf_tmpl_error_t *e; 6744 6745 if (errs == NULL) 6746 return; 6747 6748 for (i = 0; i < errs->tes_num_errs; ++i) { 6749 e = errs->tes_errs[i]; 6750 if (errs->tes_flag != 0) { 6751 free((char *)e->te_pg_name); 6752 free((char *)e->te_prop_name); 6753 free((char *)e->te_ev1); 6754 free((char *)e->te_ev2); 6755 free((char *)e->te_actual); 6756 free((char *)e->te_tmpl_fmri); 6757 free((char *)e->te_tmpl_pg_name); 6758 free((char *)e->te_tmpl_pg_type); 6759 free((char *)e->te_tmpl_prop_name); 6760 free((char *)e->te_tmpl_prop_type); 6761 } 6762 free(e); 6763 } 6764 free((char *)errs->tes_fmri); 6765 free((char *)errs->tes_prefix); 6766 free(errs->tes_errs); 6767 free(errs); 6768 } 6769 6770 int 6771 scf_tmpl_error_source_fmri(const scf_tmpl_error_t *err, char **fmri) 6772 { 6773 assert(err != NULL); 6774 switch (err->te_type) { 6775 case SCF_TERR_MISSING_PG: 6776 case SCF_TERR_WRONG_PG_TYPE: 6777 case SCF_TERR_MISSING_PROP: 6778 case SCF_TERR_WRONG_PROP_TYPE: 6779 case SCF_TERR_CARDINALITY_VIOLATION: 6780 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED: 6781 case SCF_TERR_RANGE_VIOLATION: 6782 case SCF_TERR_PROP_TYPE_MISMATCH: 6783 case SCF_TERR_VALUE_OUT_OF_RANGE: 6784 case SCF_TERR_INVALID_VALUE: 6785 case SCF_TERR_PG_REDEFINE: 6786 *fmri = (char *)err->te_tmpl_fmri; 6787 return (0); 6788 /*NOTREACHED*/ 6789 default: 6790 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 6791 } 6792 return (-1); 6793 } 6794 6795 int 6796 scf_tmpl_error_type(const scf_tmpl_error_t *err, scf_tmpl_error_type_t *type) 6797 { 6798 assert(err != NULL); 6799 switch (err->te_type) { 6800 case SCF_TERR_MISSING_PG: 6801 case SCF_TERR_WRONG_PG_TYPE: 6802 case SCF_TERR_MISSING_PROP: 6803 case SCF_TERR_WRONG_PROP_TYPE: 6804 case SCF_TERR_CARDINALITY_VIOLATION: 6805 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED: 6806 case SCF_TERR_RANGE_VIOLATION: 6807 case SCF_TERR_PROP_TYPE_MISMATCH: 6808 case SCF_TERR_VALUE_OUT_OF_RANGE: 6809 case SCF_TERR_INVALID_VALUE: 6810 case SCF_TERR_PG_REDEFINE: 6811 *type = err->te_type; 6812 return (0); 6813 /*NOTREACHED*/ 6814 default: 6815 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 6816 } 6817 return (-1); 6818 } 6819 6820 int 6821 scf_tmpl_error_pg_tmpl(const scf_tmpl_error_t *err, char **name, char **type) 6822 { 6823 assert(err != NULL); 6824 switch (err->te_type) { 6825 case SCF_TERR_MISSING_PG: 6826 case SCF_TERR_WRONG_PG_TYPE: 6827 case SCF_TERR_MISSING_PROP: 6828 case SCF_TERR_WRONG_PROP_TYPE: 6829 case SCF_TERR_CARDINALITY_VIOLATION: 6830 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED: 6831 case SCF_TERR_RANGE_VIOLATION: 6832 case SCF_TERR_PROP_TYPE_MISMATCH: 6833 case SCF_TERR_VALUE_OUT_OF_RANGE: 6834 case SCF_TERR_INVALID_VALUE: 6835 case SCF_TERR_PG_REDEFINE: 6836 if (err->te_tmpl_pg_name != NULL && 6837 err->te_tmpl_pg_type != NULL) { 6838 if (name != NULL) 6839 *name = (char *)err->te_tmpl_pg_name; 6840 if (type != NULL) 6841 *type = (char *)err->te_tmpl_pg_type; 6842 return (0); 6843 } 6844 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 6845 break; 6846 default: 6847 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 6848 } 6849 return (-1); 6850 } 6851 6852 int 6853 scf_tmpl_error_pg(const scf_tmpl_error_t *err, char **name, char **type) 6854 { 6855 assert(err != NULL); 6856 switch (err->te_type) { 6857 case SCF_TERR_WRONG_PG_TYPE: 6858 if (err->te_pg_name != NULL && 6859 err->te_actual != NULL) { 6860 if (name != NULL) 6861 *name = (char *)err->te_pg_name; 6862 if (type != NULL) 6863 *type = (char *)err->te_actual; 6864 return (0); 6865 } 6866 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 6867 break; 6868 case SCF_TERR_WRONG_PROP_TYPE: 6869 case SCF_TERR_CARDINALITY_VIOLATION: 6870 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED: 6871 case SCF_TERR_RANGE_VIOLATION: 6872 if (err->te_pg_name != NULL && 6873 err->te_tmpl_pg_type != NULL) { 6874 if (name != NULL) 6875 *name = (char *)err->te_pg_name; 6876 if (type != NULL) 6877 *type = (char *)err->te_tmpl_pg_type; 6878 return (0); 6879 } 6880 /*FALLTHROUGH*/ 6881 case SCF_TERR_MISSING_PROP: 6882 case SCF_TERR_MISSING_PG: 6883 case SCF_TERR_PROP_TYPE_MISMATCH: 6884 case SCF_TERR_VALUE_OUT_OF_RANGE: 6885 case SCF_TERR_INVALID_VALUE: 6886 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 6887 break; 6888 case SCF_TERR_PG_REDEFINE: 6889 if (err->te_ev1 != NULL && err->te_ev2 != NULL) { 6890 if (name != NULL) 6891 *name = (char *)err->te_ev1; 6892 if (type != NULL) 6893 *type = (char *)err->te_ev2; 6894 return (0); 6895 } 6896 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 6897 break; 6898 default: 6899 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 6900 } 6901 return (-1); 6902 } 6903 6904 int 6905 scf_tmpl_error_prop_tmpl(const scf_tmpl_error_t *err, char **name, char **type) 6906 { 6907 assert(err != NULL); 6908 switch (err->te_type) { 6909 case SCF_TERR_MISSING_PROP: 6910 case SCF_TERR_WRONG_PROP_TYPE: 6911 case SCF_TERR_CARDINALITY_VIOLATION: 6912 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED: 6913 case SCF_TERR_RANGE_VIOLATION: 6914 case SCF_TERR_PROP_TYPE_MISMATCH: 6915 case SCF_TERR_VALUE_OUT_OF_RANGE: 6916 case SCF_TERR_INVALID_VALUE: 6917 if (err->te_tmpl_prop_name != NULL && 6918 err->te_tmpl_prop_type != NULL) { 6919 if (name != NULL) 6920 *name = (char *)err->te_tmpl_prop_name; 6921 if (type != NULL) 6922 *type = (char *)err->te_tmpl_prop_type; 6923 return (0); 6924 } 6925 /*FALLTHROUGH*/ 6926 case SCF_TERR_MISSING_PG: 6927 case SCF_TERR_WRONG_PG_TYPE: 6928 case SCF_TERR_PG_REDEFINE: 6929 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 6930 break; 6931 default: 6932 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 6933 } 6934 return (-1); 6935 } 6936 6937 int 6938 scf_tmpl_error_prop(const scf_tmpl_error_t *err, char **name, char **type) 6939 { 6940 assert(err != NULL); 6941 switch (err->te_type) { 6942 case SCF_TERR_WRONG_PROP_TYPE: 6943 case SCF_TERR_CARDINALITY_VIOLATION: 6944 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED: 6945 case SCF_TERR_RANGE_VIOLATION: 6946 if (err->te_prop_name != NULL && 6947 err->te_tmpl_prop_type != NULL) { 6948 if (name != NULL) 6949 *name = (char *)err->te_prop_name; 6950 if (type != NULL) 6951 *type = (char *)err->te_tmpl_prop_type; 6952 return (0); 6953 } 6954 /*FALLTHROUGH*/ 6955 case SCF_TERR_MISSING_PG: 6956 case SCF_TERR_WRONG_PG_TYPE: 6957 case SCF_TERR_MISSING_PROP: 6958 case SCF_TERR_PROP_TYPE_MISMATCH: 6959 case SCF_TERR_VALUE_OUT_OF_RANGE: 6960 case SCF_TERR_INVALID_VALUE: 6961 case SCF_TERR_PG_REDEFINE: 6962 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 6963 break; 6964 default: 6965 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 6966 } 6967 return (-1); 6968 } 6969 6970 int 6971 scf_tmpl_error_value(const scf_tmpl_error_t *err, char **val) 6972 { 6973 assert(err != NULL); 6974 switch (err->te_type) { 6975 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED: 6976 case SCF_TERR_RANGE_VIOLATION: 6977 case SCF_TERR_VALUE_OUT_OF_RANGE: 6978 case SCF_TERR_INVALID_VALUE: 6979 if (err->te_actual != NULL) { 6980 if (val != NULL) 6981 *val = (char *)err->te_actual; 6982 return (0); 6983 } 6984 /*FALLTHROUGH*/ 6985 case SCF_TERR_MISSING_PG: 6986 case SCF_TERR_WRONG_PG_TYPE: 6987 case SCF_TERR_MISSING_PROP: 6988 case SCF_TERR_WRONG_PROP_TYPE: 6989 case SCF_TERR_CARDINALITY_VIOLATION: 6990 case SCF_TERR_PROP_TYPE_MISMATCH: 6991 case SCF_TERR_PG_REDEFINE: 6992 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 6993 break; 6994 default: 6995 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 6996 } 6997 return (-1); 6998 } 6999 7000 const char * 7001 scf_tmpl_visibility_to_string(uint8_t vis) 7002 { 7003 if (vis == SCF_TMPL_VISIBILITY_READONLY) 7004 return (SCF_TM_VISIBILITY_READONLY); 7005 else if (vis == SCF_TMPL_VISIBILITY_HIDDEN) 7006 return (SCF_TM_VISIBILITY_HIDDEN); 7007 else if (vis == SCF_TMPL_VISIBILITY_READWRITE) 7008 return (SCF_TM_VISIBILITY_READWRITE); 7009 else 7010 return ("unknown"); 7011 } 7012