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