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