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