dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / libscf / common / scf_tmpl.c
blobe386c9123625b3f25b86fe29ad5ac5326824cefc
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2012 Milan Jurik. All rights reserved.
27 * scf_tmpl.c
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.
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().
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.).
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.
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.
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.
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>
75 #define SCF_TMPL_PG_COMMON_NAME_C "common_name_C"
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
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
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;
101 #define SCF_WALK_ERROR -1
102 #define SCF_WALK_NEXT 0
103 #define SCF_WALK_DONE 1
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;
117 typedef struct pg_tmpl_walk pg_tmpl_walk_t;
119 typedef int walk_template_inst_func_t(scf_service_t *_svc,
120 scf_instance_t *_inst, pg_tmpl_walk_t *p);
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;
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.
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,
150 * int ismember()
152 * Returns 1 if the supplied error is a member of the error array, 0
153 * if it is not.
156 ismember(const scf_error_t error, const scf_error_t error_array[])
158 int i;
160 for (i = 0; error_array[i] != 0; ++i) {
161 if (error == error_array[i])
162 return (1);
165 return (0);
169 * char *_scf_tmpl_get_fmri()
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().
174 * On failure, returns NULL and sets scf_error() to _CONNECTION_BROKEN,
175 * _DELETED, or _NO_MEMORY.
177 static char *
178 _scf_tmpl_get_fmri(const scf_pg_tmpl_t *t)
180 ssize_t sz = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH) + 1;
181 int r;
182 char *buf = malloc(sz);
184 assert(t->pt_svc != NULL || t->pt_inst != NULL);
185 assert(t->pt_svc == NULL || t->pt_inst == NULL);
187 if (buf == NULL) {
188 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
189 return (buf);
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);
197 if (r == -1) {
198 if (ismember(scf_error(), errors_server)) {
199 free(buf);
200 buf = NULL;
201 } else {
202 assert(0);
203 abort();
207 return (buf);
211 * char *_scf_get_pg_type()
213 * Given a propertygroup, returns an allocated string containing the
214 * type. The string must be freed with free().
216 * On failure, returns NULL and sets scf_error() to: _CONNECTION_BROKEN,
217 * _DELETED, or _NO_MEMORY.
219 static char *
220 _scf_get_pg_type(scf_propertygroup_t *pg)
222 ssize_t sz = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH) + 1;
223 char *buf = malloc(sz);
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();
237 return (buf);
241 * char *_scf_get_prop_name()
243 * Given a property, returns the name in an allocated string. The string must
244 * be freed with free().
246 * On error, returns NULL and sets scf_error() to _CONNECTION_BROKEN,
247 * _DELETED, or _NO_MEMORY.
249 static char *
250 _scf_get_prop_name(scf_property_t *prop)
252 ssize_t sz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
253 char *buf = malloc(sz);
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();
267 return (buf);
271 * char *_scf_get_prop_type()
273 * Given a property, returns the type in an allocated string. The string must
274 * be freed with free().
276 * On error, returns NULL and sets scf_error() to _CONNECTION_BROKEN,
277 * _DELETED, or _NO_MEMORY.
279 static char *
280 _scf_get_prop_type(scf_property_t *prop)
282 scf_type_t type;
283 char *ret;
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();
294 ret = strdup(scf_type_to_string(type));
295 if (ret == NULL)
296 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
298 return (ret);
302 * int _read_single_value_from_pg()
304 * Reads a single value from the pg and property name specified. On success,
305 * returns an allocated value that must be freed.
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
326 static int
327 _read_single_value_from_pg(scf_propertygroup_t *pg, const char *prop_name,
328 scf_value_t **val)
330 scf_handle_t *h;
331 scf_property_t *prop;
332 int ret = 0;
334 assert(val != NULL);
335 if ((h = scf_pg_handle(pg)) == NULL) {
336 assert(scf_error() == SCF_ERROR_HANDLE_DESTROYED);
337 return (-1);
340 prop = scf_property_create(h);
341 *val = scf_value_create(h);
343 if (prop == NULL || *val == NULL) {
344 assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT);
345 goto read_single_value_from_pg_fail;
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;
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;
359 goto read_single_value_from_pg_done;
361 read_single_value_from_pg_fail:
362 scf_value_destroy(*val);
363 *val = NULL;
364 ret = -1;
366 read_single_value_from_pg_done:
367 scf_property_destroy(prop);
368 return (ret);
372 * char *_scf_read_single_astring_from_pg()
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().
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
397 char *
398 _scf_read_single_astring_from_pg(scf_propertygroup_t *pg, const char *prop_name)
400 scf_value_t *val;
401 char *ret = NULL;
402 ssize_t rsize = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH) + 1;
404 assert(rsize != 0);
405 if (_read_single_value_from_pg(pg, prop_name, &val) == -1)
406 return (NULL);
408 ret = malloc(rsize);
409 if (ret == NULL) {
410 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
411 goto cleanup;
414 if (scf_value_get_astring(val, ret, rsize) < 0) {
415 assert(scf_error() != SCF_ERROR_NOT_SET);
416 free(ret);
417 ret = NULL;
420 cleanup:
421 scf_value_destroy(val);
422 return (ret);
426 * char *_scf_read_tmpl_prop_type_as_string()
428 * Reads the property type and returns it as an allocated string. The string
429 * must be freed with free().
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.
435 char *
436 _scf_read_tmpl_prop_type_as_string(const scf_prop_tmpl_t *pt)
438 char *type;
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);
452 case SCF_ERROR_INVALID_ARGUMENT:
453 case SCF_ERROR_NOT_SET:
454 default:
455 assert(0);
456 abort();
460 return (type);
464 * int _read_single_boolean_from_pg()
466 * Reads a boolean from the pg and property name specified.
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
488 static int
489 _read_single_boolean_from_pg(scf_propertygroup_t *pg, const char *prop_name,
490 uint8_t *bool)
492 scf_value_t *val;
493 int ret = 0;
495 if (_read_single_value_from_pg(pg, prop_name, &val) == -1)
496 return (-1);
498 if (scf_value_get_boolean(val, bool) < 0) {
499 assert(scf_error() != SCF_ERROR_NOT_SET);
500 ret = -1;
503 scf_value_destroy(val);
504 return (ret);
508 * static char ** _append_astrings_values()
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.
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
530 static char **
531 _append_astrings_values(scf_propertygroup_t *pg, const char *prop_name,
532 scf_values_t *vals)
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;
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);
552 } else {
554 * The array may be bigger, but it is irrelevant since
555 * we will always re-allocate a new one.
557 cursz = count;
560 if ((h = scf_pg_handle(pg)) == NULL) {
561 assert(scf_error() == SCF_ERROR_HANDLE_DESTROYED);
562 return (NULL);
565 prop = scf_property_create(h);
566 val = scf_value_create(h);
567 iter = scf_iter_create(h);
569 if (prop == NULL || val == NULL || iter == NULL) {
570 assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT);
571 goto append_single_astring_from_pg_fail;
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;
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;
585 while ((err = scf_iter_next_value(iter, val)) == 1) {
586 int flag;
587 int r;
589 if (count + 1 >= cursz) {
590 void *aux;
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;
597 (void) memcpy(aux, vals->values.v_astring,
598 count * sizeof (char *));
599 free(vals->values.v_astring);
600 vals->values.v_astring = aux;
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;
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;
616 assert(scf_error() != SCF_ERROR_NOT_SET);
617 goto append_single_astring_from_pg_fail;
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;
628 if (flag == 1)
629 continue;
631 count++;
634 vals->value_count = count;
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;
645 goto append_single_astring_from_pg_done;
647 append_single_astring_from_pg_fail:
648 for (i = 0; i <= count; ++i) {
649 free(vals->values.v_astring[i]);
650 vals->values.v_astring[i] = NULL;
652 free(vals->values.v_astring);
653 vals->values.v_astring = NULL;
654 vals->value_count = 0;
656 append_single_astring_from_pg_done:
657 scf_iter_destroy(iter);
658 scf_property_destroy(prop);
659 scf_value_destroy(val);
660 return (vals->values.v_astring);
664 * Returns NULL on failure, sets scf_error() to:
665 * SCF_ERROR_BACKEND_ACCESS
666 * SCF_ERROR_CONNECTION_BROKEN
667 * SCF_ERROR_DELETED
668 * SCF_ERROR_HANDLE_DESTROYED
669 * SCF_ERROR_INTERNAL
670 * SCF_ERROR_INVALID_ARGUMENT
671 * prop_name is not a valid property name.
672 * SCF_ERROR_NO_MEMORY
673 * SCF_ERROR_NO_RESOURCES
674 * SCF_ERROR_NOT_BOUND
675 * SCF_ERROR_NOT_FOUND
676 * SCF_ERROR_NOT_SET
677 * SCF_ERROR_PERMISSION_DENIED
678 * SCF_ERROR_TYPE_MISMATCH
680 static char **
681 _read_astrings_values(scf_propertygroup_t *pg, const char *prop_name,
682 scf_values_t *vals)
684 assert(vals != NULL);
685 vals->value_count = 0;
686 vals->value_type = SCF_TYPE_ASTRING;
687 vals->reserved = NULL;
688 return (_append_astrings_values(pg, prop_name, vals));
691 void
692 _scf_sanitize_locale(char *locale)
694 for (; *locale != '\0'; locale++)
695 if (!isalnum(*locale) && *locale != '_')
696 *locale = '_';
700 * The returned string needs to be freed by the caller
701 * Returns NULL on failure. Sets scf_error() to:
702 * SCF_ERROR_NO_MEMORY
703 * SCF_ERROR_INVALID_ARGUMENT
704 * Name isn't short enough to add the locale to.
706 static char *
707 _add_locale_to_name(const char *name, const char *locale)
709 char *lname = NULL;
710 ssize_t lsz;
711 char *loc;
713 if (locale == NULL)
714 locale = setlocale(LC_MESSAGES, NULL);
715 loc = strdup(locale);
716 if (loc == NULL) {
717 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
718 return (NULL);
719 } else {
720 _scf_sanitize_locale(loc);
723 lsz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
724 lname = malloc(lsz);
725 if (lname == NULL) {
726 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
727 goto cleanup;
730 (void) strlcpy(lname, name, lsz);
731 if (strlcat(lname, loc, lsz) >= lsz) {
732 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
733 free(lname);
734 lname = NULL;
736 cleanup:
737 free(loc);
739 return (lname);
743 * char *_tmpl_pg_name(pg, type, use_type)
745 * pg and type can both be NULL. Returns the name of the most specific
746 * template property group name based on the inputs.
747 * If use_type is set and pg is not NULL, a property group name for a
748 * property group template that has type defined is returned, even if no
749 * type is provided.
751 * Returns NULL on failure and sets scf_error() to:
752 * SCF_ERROR_INVALID_ARGUMENT
753 * can't combine the arguments and get a reasonable length name
754 * SCF_ERROR_NO_MEMORY
757 static char *
758 _tmpl_pg_name(const char *pg, const char *type, int use_type)
760 char *name;
761 ssize_t limit, size = 0;
763 limit = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
764 name = malloc(limit);
765 if (name == NULL) {
766 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
767 return (NULL);
770 if (pg == NULL && type == NULL) {
771 if (strlcpy(name, SCF_PG_TM_PG_PATTERN_PREFIX, limit) >=
772 limit) {
773 assert(0);
774 abort();
776 return (name);
777 } else if (pg != NULL && type != NULL) {
778 size = snprintf(name, limit, "%s%s",
779 SCF_PG_TM_PG_PATTERN_NT_PREFIX, pg);
780 } else if (pg != NULL && type == NULL && use_type == 1) {
781 size = snprintf(name, limit, "%s%s",
782 SCF_PG_TM_PG_PATTERN_NT_PREFIX, pg);
783 } else if (pg != NULL && type == NULL) {
784 size = snprintf(name, limit, "%s%s",
785 SCF_PG_TM_PG_PATTERN_N_PREFIX, pg);
786 } else if (type != NULL && pg == NULL) {
787 size = snprintf(name, limit, "%s%s",
788 SCF_PG_TM_PG_PATTERN_T_PREFIX, type);
789 } else {
790 assert(0);
791 abort();
794 if (size >= limit) {
795 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
796 free(name);
797 return (NULL);
798 } else {
799 return (name);
804 * _scf_get_pg_name()
805 * Gets the name of the supplied property group. On success, returns an
806 * allocated string. The string must be freed by free().
808 * Returns NULL on failure and sets scf_error() to _CONNECTION_BROKEN,
809 * _DELETED, or _NO_MEMORY.
811 static char *
812 _scf_get_pg_name(scf_propertygroup_t *pg)
814 ssize_t sz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
815 char *buf = malloc(sz);
817 if (buf == NULL) {
818 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
819 } else if (scf_pg_get_name(pg, buf, sz) == -1) {
820 if (ismember(scf_error(), errors_server)) {
821 free(buf);
822 buf = NULL;
823 } else {
824 assert(0);
825 abort();
829 return (buf);
833 * char *_tmpl_prop_name()
835 * Returns the name of the property template prop (which is the name of
836 * the property template property group) in the property group
837 * template t. Returns NULL on failure and sets scf_error() to:
838 * SCF_ERROR_CONNECTION_BROKEN
839 * SCF_ERROR_DELETED
840 * SCF_ERROR_INVALID_ARGUMENT
841 * can't combine the arguments and get a reasonable length name
842 * SCF_ERROR_NO_MEMORY
844 static char *
845 _tmpl_prop_name(const char *prop, scf_pg_tmpl_t *t)
847 char *name = NULL, *pg_name = NULL;
848 size_t prefix_size;
849 ssize_t limit, size = 0;
851 assert(prop != NULL);
852 assert(t->pt_pg != NULL);
854 limit = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
855 name = malloc(limit);
856 if (name == NULL) {
857 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
858 return (NULL);
861 if ((pg_name = _scf_get_pg_name(t->pt_pg)) == NULL) {
862 free(name);
863 return (NULL);
866 prefix_size = strlen(SCF_PG_TM_PG_PAT_BASE);
867 if (strncmp(pg_name, SCF_PG_TM_PG_PAT_BASE, prefix_size) != 0) {
868 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
869 free(name);
870 free(pg_name);
871 return (NULL);
874 size = snprintf(name, limit, "%s%s_%s", SCF_PG_TM_PROP_PATTERN_PREFIX,
875 pg_name + prefix_size, prop);
877 if (size >= limit) {
878 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
879 free(name);
880 free(pg_name);
881 return (NULL);
882 } else {
883 free(pg_name);
884 return (name);
889 * int _get_snapshot()
891 * Gets the specified snapshot. If "snapshot" isn't defined, use the
892 * running snapshot. If the snapshot isn't found, that may or may
893 * not be an error depending on the caller. Return 0 in that case,
894 * but leave scf_error() set to SCF_ERROR_NOT_FOUND. On all other
895 * errors, set scf_error() to:
896 * SCF_ERROR_BACKEND_ACCESS
897 * SCF_ERROR_CONNECTION_BROKEN
898 * SCF_ERROR_DELETED
899 * SCF_ERR_HANDLE_DESTROYED
900 * SCF_ERROR_INTERNAL
901 * SCF_ERROR_INVALID_ARGUMENT
902 * The handle argument is NULL, or snaphot is not a valid snapshot name
903 * SCF_ERROR_NO_MEMORY
904 * SCF_ERROR_NO_RESOURCES
905 * SCF_ERROR_NOT_BOUND
906 * SCF_ERROR_NOT_FOUND
908 static int
909 _get_snapshot(scf_instance_t *inst, const char *snapshot,
910 scf_snapshot_t **snap)
912 int err;
913 scf_handle_t *h;
915 h = scf_instance_handle(inst);
916 if (h == NULL) {
917 *snap = NULL;
918 return (-1);
921 if ((*snap = scf_snapshot_create(h)) == NULL) {
922 return (-1);
925 /* Use running snapshot by default. */
926 if (snapshot == NULL)
927 err = scf_instance_get_snapshot(inst, "running", *snap);
928 else
929 err = scf_instance_get_snapshot(inst, snapshot, *snap);
931 if (err != 0) {
932 if (ismember(scf_error(), errors_server)) {
933 scf_snapshot_destroy(*snap);
934 *snap = NULL;
935 return (-1);
936 } else switch (scf_error()) {
937 case SCF_ERROR_INVALID_ARGUMENT:
938 scf_snapshot_destroy(*snap);
939 *snap = NULL;
940 return (-1);
942 case SCF_ERROR_NOT_FOUND:
943 scf_snapshot_destroy(*snap);
944 *snap = NULL;
945 return (0);
947 case SCF_ERROR_NOT_SET:
948 case SCF_ERROR_HANDLE_MISMATCH:
949 default:
950 assert(0);
951 abort();
956 * Explicitly set SCF_ERROR_NONE so that the SCF_ERROR_NOT_FOUND
957 * return above is explicitly guaranteed to be from
958 * scf_instance_get_snapshot().
960 (void) scf_set_error(SCF_ERROR_NONE);
961 return (0);
965 * Returns NULL on error, sets scf_error() to:
966 * SCF_ERROR_BACKEND_ACCESS
967 * SCF_ERROR_CONNECTION_BROKEN
968 * SCF_ERROR_CONSTRAINT_VIOLATED
969 * The restarter's FMRI does not match an existing instance.
970 * SCF_ERROR_DELETED
971 * SCF_ERROR_HANDLE_DESTROYED
972 * SCF_ERROR_INTERNAL
973 * SCF_ERROR_INVALID_ARGUMENT
974 * The restarter's FMRI is not a valid FMRI.
975 * SCF_ERROR_NO_MEMORY
976 * SCF_ERROR_NO_RESOURCES
977 * SCF_ERROR_NOT_BOUND
978 * SCF_ERROR_NOT_FOUND
979 * Property doesn't exist or exists and has no value.
980 * SCF_ERROR_TEMPLATE_INVALID
981 * restarter property is not SCF_TYPE_ASTRING or has more than one value
983 static scf_instance_t *
984 _get_restarter_inst(scf_handle_t *h, scf_service_t *svc,
985 scf_instance_t *inst, scf_snapshot_t *s)
987 char *restarter = NULL;
988 scf_instance_t *ri = NULL;
989 scf_propertygroup_t *pg = NULL;
990 int ret = 0;
992 assert(svc != NULL || inst != NULL);
993 assert(svc == NULL || inst == NULL);
995 if ((ri = scf_instance_create(h)) == NULL ||
996 (pg = scf_pg_create(h)) == NULL) {
997 assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT);
998 goto _get_restarter_inst_fail;
1001 if (inst != NULL)
1002 ret = scf_instance_get_pg_composed(inst, s, SCF_PG_GENERAL,
1003 pg);
1004 else
1005 ret = scf_service_get_pg(svc, SCF_PG_GENERAL, pg);
1007 if (ret != 0) {
1008 if (ismember(scf_error(), errors_server)) {
1009 goto _get_restarter_inst_fail;
1010 } else switch (scf_error()) {
1011 case SCF_ERROR_NOT_FOUND:
1012 /* Assume default restarter. */
1013 break;
1015 case SCF_ERROR_NOT_SET:
1016 case SCF_ERROR_HANDLE_MISMATCH:
1018 * If the arguments to the above functions
1019 * aren't derived from the same handle, there's
1020 * something wrong with the internal implementation,
1021 * not the public caller further up the chain.
1023 case SCF_ERROR_INVALID_ARGUMENT:
1024 default:
1025 assert(0);
1026 abort();
1028 } else {
1029 restarter = _scf_read_single_astring_from_pg(pg,
1030 SCF_PROPERTY_RESTARTER);
1031 /* zero length string is NOT a valid restarter */
1032 if (restarter != NULL && restarter[0] == '\0') {
1033 free(restarter);
1034 restarter = NULL;
1035 } else if (restarter == NULL) {
1036 if (ismember(scf_error(), errors_server)) {
1037 goto _get_restarter_inst_fail;
1038 } else switch (scf_error()) {
1039 case SCF_ERROR_NOT_FOUND:
1040 break;
1042 case SCF_ERROR_CONSTRAINT_VIOLATED:
1043 case SCF_ERROR_TYPE_MISMATCH:
1044 (void) scf_set_error(
1045 SCF_ERROR_TEMPLATE_INVALID);
1046 goto _get_restarter_inst_fail;
1048 case SCF_ERROR_NOT_SET:
1049 case SCF_ERROR_INVALID_ARGUMENT:
1050 default:
1051 assert(0);
1052 abort();
1057 if (restarter == NULL) {
1058 /* Use default restarter */
1059 restarter = strdup(SCF_SERVICE_STARTD);
1060 if (restarter == NULL) {
1061 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1062 goto _get_restarter_inst_fail;
1066 if (scf_handle_decode_fmri(h, restarter, NULL, NULL, ri, NULL, NULL,
1067 SCF_DECODE_FMRI_EXACT|SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) {
1068 if (ismember(scf_error(), errors_server)) {
1069 goto _get_restarter_inst_fail;
1070 } else switch (scf_error()) {
1071 case SCF_ERROR_CONSTRAINT_VIOLATED:
1072 case SCF_ERROR_INVALID_ARGUMENT:
1073 case SCF_ERROR_NOT_FOUND:
1074 goto _get_restarter_inst_fail;
1076 case SCF_ERROR_HANDLE_MISMATCH:
1077 case SCF_ERROR_NOT_SET:
1078 default:
1079 assert(0);
1080 abort();
1083 free(restarter);
1084 scf_pg_destroy(pg);
1086 return (ri);
1088 _get_restarter_inst_fail:
1089 free(restarter);
1090 scf_instance_destroy(ri);
1091 scf_pg_destroy(pg);
1092 return (NULL);
1096 * Returns NULL on error, sets scf_error() to:
1097 * SCF_ERROR_BACKEND_ACCESS
1098 * SCF_ERROR_CONNECTION_BROKEN
1099 * SCF_ERROR_CONSTRAINT_VIOLATED
1100 * Restarter property has more than one value associated with it,
1101 * or FMRI does not meet restrictions in scf_handle_decode_fmri() flags.
1102 * SCF_ERROR_DELETED
1103 * SCF_ERROR_HANDLE_DESTROYED
1104 * SCF_ERROR_INTERNAL
1105 * SCF_ERROR_INVALID_ARGUMENT
1106 * The fmri argument in scf_handle_decode_fmri() is not a valid FMRI.
1107 * SCF_ERROR_NO_MEMORY
1108 * SCF_ERROR_NO_RESOURCES
1109 * SCF_ERROR_NOT_BOUND
1110 * SCF_ERROR_NOT_FOUND
1111 * Property doesn't exist or exists and has no value.
1113 static scf_instance_t *
1114 _get_global_inst(scf_handle_t *h)
1116 scf_instance_t *ri;
1118 if ((ri = scf_instance_create(h)) == NULL) {
1119 assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT);
1120 (void) scf_set_error(SCF_ERROR_NO_RESOURCES);
1121 return (NULL);
1124 if (scf_handle_decode_fmri(h, SCF_INSTANCE_GLOBAL, NULL, NULL, ri,
1125 NULL, NULL,
1126 SCF_DECODE_FMRI_EXACT|SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) {
1127 if (ismember(scf_error(), errors_server)) {
1128 scf_instance_destroy(ri);
1129 return (NULL);
1130 } else switch (scf_error()) {
1131 case SCF_ERROR_CONSTRAINT_VIOLATED:
1132 case SCF_ERROR_INVALID_ARGUMENT:
1133 case SCF_ERROR_NOT_FOUND:
1134 scf_instance_destroy(ri);
1135 return (NULL);
1137 case SCF_ERROR_HANDLE_MISMATCH:
1138 case SCF_ERROR_NOT_SET:
1139 default:
1140 assert(0);
1141 abort();
1145 return (ri);
1149 * Call the supplied function for each of the service or instance, the
1150 * service's restarter, and the globally defined template instance.
1151 * If the function returns SCF_WALK_ERROR, the walk is ended. If
1152 * the function returns SCF_WALK_NEXT, the next entity is tried.
1154 * The function is only expected to return SCF_WALK_DONE if it has
1155 * found a property group match in the current entity, and has
1156 * populated p->pw_pg with the matching property group.
1158 * The caller of _walk_template_instances() MUST check if the passed parameters
1159 * inst and svc match the fields pw_inst and pw_svc in the resulting
1160 * pg_tmpl_walk_t and call the destructor for the unmatching objects. The walker
1161 * may silently drop them if the template definition is in the restarter or in
1162 * the global instance.
1164 static void
1165 _walk_template_instances(scf_service_t *svc, scf_instance_t *inst,
1166 scf_snapshot_t *snap, walk_template_inst_func_t *func,
1167 pg_tmpl_walk_t *p, int flag)
1169 scf_instance_t *tmpl_inst = NULL;
1170 scf_handle_t *h;
1171 int ret;
1172 char *tg = NULL;
1174 assert(svc != NULL || inst != NULL);
1175 assert(svc == NULL || inst == NULL);
1177 if (inst != NULL)
1178 h = scf_instance_handle(inst);
1179 else
1180 h = scf_service_handle(svc);
1181 if (h == NULL)
1182 goto done;
1184 /* First, use supplied service or instance */
1185 p->pw_target = SCF_TM_TARGET_THIS;
1186 ret = func(svc, inst, p);
1187 switch (ret) {
1188 case SCF_WALK_NEXT:
1189 break;
1190 case SCF_WALK_DONE:
1192 * Check that the template scoping matches and if not,
1193 * continue.
1195 assert(p->pw_pg != NULL);
1196 tg = _scf_read_single_astring_from_pg(p->pw_pg,
1197 SCF_PROPERTY_TM_TARGET);
1198 if (tg == NULL || /* scf_error() was set */
1199 (strcmp(tg, SCF_TM_TARGET_INSTANCE) != 0 &&
1200 strcmp(tg, SCF_TM_TARGET_THIS) != 0 &&
1201 (flag & SCF_PG_TMPL_FLAG_EXACT) !=
1202 SCF_PG_TMPL_FLAG_EXACT)) {
1203 scf_pg_destroy(p->pw_pg);
1204 p->pw_pg = NULL;
1205 if (tg != NULL) {
1206 free(tg);
1207 tg = NULL;
1208 break;
1211 /*FALLTHROUGH*/
1212 case SCF_WALK_ERROR:
1213 goto done;
1214 /*NOTREACHED*/
1215 default:
1216 assert(0);
1217 abort();
1220 /* Next the restarter. */
1221 p->pw_target = SCF_TM_TARGET_DELEGATE;
1222 tmpl_inst = _get_restarter_inst(h, svc, inst, snap);
1223 if (tmpl_inst != NULL) {
1224 ret = func(NULL, tmpl_inst, p);
1225 switch (ret) {
1226 case SCF_WALK_NEXT:
1227 break;
1228 case SCF_WALK_DONE:
1230 * Check that the template scoping matches and if not,
1231 * continue.
1233 assert(p->pw_pg != NULL);
1234 tg = _scf_read_single_astring_from_pg(p->pw_pg,
1235 SCF_PROPERTY_TM_TARGET);
1236 if (tg == NULL || /* scf_error() was set */
1237 strcmp(tg, SCF_TM_TARGET_DELEGATE) != 0) {
1238 scf_pg_destroy(p->pw_pg);
1239 p->pw_pg = NULL;
1240 if (tg != NULL) {
1241 free(tg);
1242 tg = NULL;
1243 break;
1246 /*FALLTHROUGH*/
1247 case SCF_WALK_ERROR:
1248 goto done;
1249 /*NOTREACHED*/
1250 default:
1251 assert(0);
1252 abort();
1256 p->pw_target = SCF_TM_TARGET_ALL;
1257 scf_instance_destroy(tmpl_inst);
1258 tmpl_inst = _get_global_inst(h);
1259 if (tmpl_inst != NULL) {
1260 ret = func(NULL, tmpl_inst, p);
1261 switch (ret) {
1262 case SCF_WALK_NEXT:
1263 break;
1264 case SCF_WALK_DONE:
1266 * Check that the template scoping matches and if not,
1267 * continue.
1269 assert(p->pw_pg != NULL);
1270 tg = _scf_read_single_astring_from_pg(p->pw_pg,
1271 SCF_PROPERTY_TM_TARGET);
1272 if (tg == NULL || /* scf_error() was set */
1273 strcmp(tg, SCF_TM_TARGET_ALL) != 0) {
1274 scf_pg_destroy(p->pw_pg);
1275 p->pw_pg = NULL;
1276 if (tg != NULL) {
1277 free(tg);
1278 tg = NULL;
1279 break;
1282 /*FALLTHROUGH*/
1283 case SCF_WALK_ERROR:
1284 goto done;
1285 /*NOTREACHED*/
1286 default:
1287 assert(0);
1288 abort();
1292 done:
1293 free(tg);
1294 if (ret != SCF_WALK_DONE)
1295 scf_instance_destroy(tmpl_inst);
1296 p->pw_target = NULL;
1300 * _get_pg() returns 0 on success and -1 on failure. Sets scf_error()
1301 * on failure.
1302 * SCF_ERROR_BACKEND_ACCESS
1303 * SCF_ERROR_CONNECTION_BROKEN
1304 * SCF_ERROR_DELETED
1305 * SCF_ERROR_HANDLE_MISMATCH
1306 * SCF_ERROR_INTERNAL
1307 * SCF_ERROR_INVALID_ARGUMENT
1308 * name is not a valid property group.
1309 * SCF_ERROR_NO_RESOURCES
1310 * SCF_ERROR_NOT_BOUND
1311 * SCF_ERROR_NOT_FOUND
1312 * SCF_ERROR_NOT_SET
1314 static int
1315 _get_pg(scf_service_t *svc, scf_instance_t *inst,
1316 const scf_snapshot_t *snap, const char *name, scf_propertygroup_t *pg)
1318 int ret;
1320 assert(svc != NULL || inst != NULL);
1321 assert(svc == NULL || inst == NULL);
1322 assert(pg != NULL);
1324 if (inst != NULL)
1325 ret = scf_instance_get_pg_composed(inst, snap, name, pg);
1326 else
1327 ret = scf_service_get_pg(svc, name, pg);
1329 return (ret);
1333 * Returns SCF_WALK_NEXT for not found, SCF_WALK_ERROR for error,
1334 * and SCF_WALK_DONE for found.
1335 * On error, destroy pg and set it to NULL.
1337 * Sets scf_error() if SCF_WALK_ERROR is returned to _BACKEND_ACCESS,
1338 * _CONNECTION_BROKEN, _INTERNAL, _INVALID_ARGUMENT (name is not a
1339 * valid property group), _NO_RESOURCES, or _NOT_BOUND.
1341 static int
1342 _lookup_pg(scf_service_t *svc, scf_instance_t *inst,
1343 const scf_snapshot_t *snap, const char *name, scf_propertygroup_t *pg)
1345 int ret;
1347 ret = _get_pg(svc, inst, snap, name, pg);
1349 if (ret == 0) {
1350 return (SCF_WALK_DONE);
1351 } else {
1352 switch (scf_error()) {
1353 case SCF_ERROR_NOT_FOUND:
1354 case SCF_ERROR_DELETED:
1355 return (SCF_WALK_NEXT);
1357 case SCF_ERROR_BACKEND_ACCESS:
1358 case SCF_ERROR_CONNECTION_BROKEN:
1359 case SCF_ERROR_INTERNAL:
1360 case SCF_ERROR_INVALID_ARGUMENT:
1361 case SCF_ERROR_NOT_BOUND:
1362 case SCF_ERROR_NO_RESOURCES:
1363 scf_pg_destroy(pg);
1364 pg = NULL;
1365 return (SCF_WALK_ERROR);
1367 case SCF_ERROR_NOT_SET:
1368 case SCF_ERROR_HANDLE_MISMATCH:
1369 default:
1370 assert(0);
1371 abort();
1375 /*NOTREACHED*/
1379 * If match, return 0. If no match, return 1. If error, return -1.
1380 * On error set scf_error() to _BACKEND_ACCESS, _CONNECTION_BROKEN,
1381 * _HANDLE_DESTROYED, _INTERNAL, _NO_MEMORY, _NO_RESOURCES, _NOT_BOUND,
1382 * _NOT_SET (property group specified by pg is not set), _PERMISSION_DENIED,
1383 * or _TEMPLATE_INVALID (target property is not SCF_TYPE_ASTRING or has
1384 * more than one value).
1386 static int
1387 check_target_match(scf_propertygroup_t *pg, const char *target)
1389 char *pg_target;
1390 int ret = 0;
1392 pg_target = _scf_read_single_astring_from_pg(pg,
1393 SCF_PROPERTY_TM_TARGET);
1394 if (pg_target == NULL) {
1395 switch (scf_error()) {
1396 case SCF_ERROR_DELETED:
1397 case SCF_ERROR_NOT_FOUND:
1398 return (1);
1400 case SCF_ERROR_CONSTRAINT_VIOLATED:
1401 case SCF_ERROR_TYPE_MISMATCH:
1402 (void) scf_set_error(
1403 SCF_ERROR_TEMPLATE_INVALID);
1404 /*FALLTHROUGH*/
1406 case SCF_ERROR_BACKEND_ACCESS:
1407 case SCF_ERROR_CONNECTION_BROKEN:
1408 case SCF_ERROR_HANDLE_DESTROYED:
1409 case SCF_ERROR_INTERNAL:
1410 case SCF_ERROR_NO_RESOURCES:
1411 case SCF_ERROR_NOT_BOUND:
1412 case SCF_ERROR_PERMISSION_DENIED:
1413 return (-1);
1415 case SCF_ERROR_NOT_SET:
1416 case SCF_ERROR_INVALID_ARGUMENT:
1417 default:
1418 assert(0);
1419 abort();
1421 /*NOTREACHED*/
1424 /* For a desired target of 'this', check for 'this' and 'instance'. */
1425 if ((strcmp(target, SCF_TM_TARGET_INSTANCE) == 0 ||
1426 strcmp(target, SCF_TM_TARGET_THIS) == 0) &&
1427 (strcmp(pg_target, SCF_TM_TARGET_INSTANCE) == 0 ||
1428 strcmp(pg_target, SCF_TM_TARGET_THIS) == 0)) {
1429 goto cleanup;
1432 if (strcmp(target, SCF_TM_TARGET_DELEGATE) == 0 &&
1433 strcmp(pg_target, SCF_TM_TARGET_DELEGATE) == 0) {
1434 goto cleanup;
1437 if (strcmp(target, SCF_TM_TARGET_ALL) == 0 &&
1438 strcmp(pg_target, SCF_TM_TARGET_ALL) == 0) {
1439 goto cleanup;
1442 ret = 1;
1443 cleanup:
1444 free(pg_target);
1445 return (ret);
1449 * Check if a matching template property group exists for each of:
1450 * name and type, name only, type only, and completely wildcarded
1451 * template.
1453 * Both pg_name and pg_type are optional.
1455 * Returns NULL on failure, sets scf_error():
1456 * SCF_ERROR_BACKEND_ACCESS
1457 * SCF_ERROR_CONNECTION_BROKEN
1458 * SCF_ERROR_DELETED
1459 * SCF_ERROR_HANDLE_DESTROYED
1460 * SCF_ERROR_INTERNAL
1461 * SCF_ERROR_INVALID_ARGUMENT
1462 * can't combine the _tmpl_pg_name arguments and get a reasonable
1463 * length name, or pg_name is not a valid property group.
1464 * SCF_ERROR_NO_MEMORY
1465 * SCF_ERROR_NO_RESOURCES
1466 * SCF_ERROR_NOT_BOUND
1467 * SCF_ERROR_NOT_FOUND
1468 * Property doesn't exist or exists and has no value.
1469 * SCF_ERROR_PERMISSION_DENIED
1470 * SCF_ERROR_TEMPLATE_INVALID
1471 * target property is not SCF_TYPE_ASTRING or has more than one value.
1473 static scf_propertygroup_t *
1474 _find_template_pg_match(scf_service_t *svc, scf_instance_t *inst,
1475 const scf_snapshot_t *snap, const char *pg_name, const char *pg_type,
1476 const char *target, char **tmpl_pg_name)
1478 int ret, r;
1479 scf_propertygroup_t *pg = NULL;
1480 scf_handle_t *h;
1481 scf_iter_t *iter;
1482 char *name, *type;
1484 assert(inst != NULL || svc != NULL);
1485 assert(inst == NULL || svc == NULL);
1487 if (inst != NULL)
1488 h = scf_instance_handle(inst);
1489 else
1490 h = scf_service_handle(svc);
1491 if (h == NULL) {
1492 return (NULL);
1495 if ((pg = scf_pg_create(h)) == NULL ||
1496 (iter = scf_iter_create(h)) == NULL) {
1497 assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT);
1498 scf_pg_destroy(pg);
1499 return (NULL);
1503 * We're going to walk through the possible pg templates that
1504 * could match the supplied name and type. We do this
1505 * by explicit name lookups when possible to avoid having to
1506 * keep track of a most-explicit-match during iteration.
1509 /* First look for a template with name and type set and matching. */
1510 *tmpl_pg_name = _tmpl_pg_name(pg_name, pg_type, 1);
1511 if (*tmpl_pg_name == NULL)
1512 goto fail;
1513 ret = _lookup_pg(svc, inst, snap, *tmpl_pg_name, pg);
1514 if (ret != SCF_WALK_NEXT) {
1515 if (pg != NULL) {
1516 if ((r = check_target_match(pg, target)) == 0)
1517 goto done;
1518 else if (r == -1)
1519 goto fail;
1520 } else {
1521 goto done;
1524 free(*tmpl_pg_name);
1527 * Need to search on a name-only match before searching on
1528 * type matches.
1531 *tmpl_pg_name = _tmpl_pg_name(pg_name, NULL, 0);
1532 if (*tmpl_pg_name == NULL)
1533 goto fail;
1534 ret = _lookup_pg(svc, inst, snap, *tmpl_pg_name, pg);
1535 if (ret != SCF_WALK_NEXT) {
1536 if (pg != NULL) {
1537 if ((r = check_target_match(pg, target)) == 0)
1538 goto done;
1539 else if (r == -1)
1540 goto fail;
1541 } else {
1542 goto done;
1545 free(*tmpl_pg_name);
1547 /* Next, see if there's an "nt" template where the type matches. */
1548 if (pg_type != NULL && pg_name == NULL) {
1549 if (inst != NULL)
1550 ret = scf_iter_instance_pgs_typed_composed(iter, inst,
1551 snap, SCF_GROUP_TEMPLATE_PG_PATTERN);
1552 else
1553 ret = scf_iter_service_pgs_typed(iter, svc,
1554 SCF_GROUP_TEMPLATE_PG_PATTERN);
1556 if (ret != 0) {
1557 if (ismember(scf_error(), errors_server)) {
1558 goto fail;
1559 } else {
1560 assert(0);
1561 abort();
1565 while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
1566 /* Make sure this is a name and type specified pg. */
1567 name = _scf_read_single_astring_from_pg(pg,
1568 SCF_PROPERTY_TM_NAME);
1569 if (name == NULL)
1570 continue;
1571 type = _scf_read_single_astring_from_pg(pg,
1572 SCF_PROPERTY_TM_TYPE);
1573 if (type == NULL) {
1574 free(name);
1575 continue;
1577 if (strcmp(pg_type, type) == 0 &&
1578 check_target_match(pg, target) == 0) {
1579 *tmpl_pg_name = name;
1580 free(type);
1581 goto done;
1583 free(type);
1584 free(name);
1586 if (ret == -1) {
1587 if (ismember(scf_error(), errors_server)) {
1588 goto fail;
1589 } else {
1590 assert(0);
1591 abort();
1596 *tmpl_pg_name = _tmpl_pg_name(NULL, pg_type, 0);
1597 if (*tmpl_pg_name == NULL)
1598 goto fail;
1599 ret = _lookup_pg(svc, inst, snap, *tmpl_pg_name, pg);
1600 if (ret != SCF_WALK_NEXT) {
1601 if (pg != NULL) {
1602 if ((r = check_target_match(pg, target)) == 0)
1603 goto done;
1604 else if (r == -1)
1605 goto fail;
1606 } else {
1607 goto done;
1610 free(*tmpl_pg_name);
1612 *tmpl_pg_name = _tmpl_pg_name(NULL, NULL, 0);
1613 if (*tmpl_pg_name == NULL)
1614 goto fail;
1615 ret = _lookup_pg(svc, inst, snap, *tmpl_pg_name, pg);
1616 if (ret != SCF_WALK_NEXT) {
1617 if (pg != NULL) {
1618 if ((r = check_target_match(pg, target)) == 0)
1619 goto done;
1620 else if (r == -1)
1621 goto fail;
1622 } else {
1623 goto done;
1627 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
1628 fail:
1629 scf_pg_destroy(pg);
1630 free(*tmpl_pg_name);
1631 *tmpl_pg_name = NULL;
1632 pg = NULL;
1633 done:
1634 if (ret == SCF_WALK_ERROR)
1635 free(*tmpl_pg_name);
1636 scf_iter_destroy(iter);
1637 return (pg);
1641 * Finds the pg match in either the supplied service or instance.
1642 * Returns SCF_WALK_ERROR, SCF_WALK_NEXT, or SCF_WALK_DONE.
1643 * If returning SCF_WALK_ERROR, sets scf_error():
1644 * SCF_ERROR_BACKEND_ACCESS
1645 * SCF_ERROR_CONNECTION_BROKEN
1646 * SCF_ERROR_DELETED
1647 * SCF_ERROR_HANDLE_DESTROYED
1648 * SCF_ERROR_INTERNAL
1649 * SCF_ERROR_INVALID_ARGUMENT
1650 * The snaphot is not a valid snapshot name,
1651 * or can't create a reasonable property group template name.
1652 * SCF_ERROR_NO_MEMORY
1653 * SCF_ERROR_NO_RESOURCES
1654 * SCF_ERROR_NOT_BOUND
1655 * SCF_ERROR_NOT_FOUND
1656 * Property doesn't exist or exists and has no value.
1657 * SCF_ERROR_PERMISSION_DENIED
1658 * SCF_ERROR_TEMPLATE_INVALID
1659 * target property is not SCF_TYPE_ASTRING or has more than one value.
1661 static int
1662 find_pg_match(scf_service_t *svc, scf_instance_t *inst, pg_tmpl_walk_t *p)
1664 scf_snapshot_t *tmpl_snap = NULL;
1665 scf_propertygroup_t *pg;
1666 scf_handle_t *h;
1667 char *tmpl_pg_name;
1669 assert(svc != NULL || inst != NULL);
1670 assert(svc == NULL || inst == NULL);
1672 if (inst != NULL)
1673 h = scf_instance_handle(inst);
1674 else
1675 h = scf_service_handle(svc);
1676 if (h == NULL)
1677 return (SCF_WALK_ERROR);
1679 if (p->pw_snapname != NULL) {
1680 if (_get_snapshot(inst, p->pw_snapname, &tmpl_snap) == -1)
1681 return (SCF_WALK_ERROR);
1683 pg = _find_template_pg_match(svc, inst, tmpl_snap, p->pw_pgname,
1684 p->pw_pgtype, p->pw_target, &tmpl_pg_name);
1686 if (pg != NULL) {
1687 p->pw_snap = tmpl_snap;
1688 p->pw_pg = pg;
1689 p->pw_tmpl_pgname = tmpl_pg_name;
1690 p->pw_inst = inst;
1691 p->pw_svc = svc;
1692 return (SCF_WALK_DONE);
1695 scf_snapshot_destroy(tmpl_snap);
1696 return (SCF_WALK_NEXT);
1700 * return 0 on success and -1 on failure.
1701 * SCF_ERROR_CONNECTION_BROKEN
1702 * SCF_ERROR_DELETED
1703 * SCF_ERROR_HANDLE_DESTROYED
1704 * SCF_ERROR_HANDLE_MISMATCH
1705 * SCF_ERROR_INTERNAL
1706 * SCF_ERROR_INVALID_ARGUMENT
1707 * FMRI argument, snapshot name, pg_name, or pg is invalid.
1708 * SCF_ERROR_NO_MEMORY
1709 * SCF_ERROR_NO_RESOURCES
1710 * SCF_ERROR_NOT_BOUND
1711 * SCF_ERROR_NOT_FOUND
1712 * SCF_ERROR_NOT_SET
1715 scf_tmpl_get_by_pg(scf_propertygroup_t *pg, scf_pg_tmpl_t *pg_tmpl, int flags)
1717 char *fmribuf = NULL, *snapbuf = NULL, *pg_name = NULL, *pg_type = NULL;
1718 int ret;
1719 ssize_t fbufsz = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH) + 1;
1720 ssize_t nbufsz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
1721 ssize_t tbufsz = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH) + 1;
1722 scf_instance_t *inst = NULL;
1723 scf_snaplevel_t *snaplvl = NULL;
1724 scf_service_t *svc = NULL;
1725 scf_handle_t *h;
1726 scf_snapshot_t *snap = NULL;
1727 pg_tmpl_walk_t *p = NULL;
1729 assert(fbufsz != 0 && nbufsz != 0 && tbufsz != 0);
1731 scf_tmpl_pg_reset(pg_tmpl);
1733 if ((h = scf_pg_handle(pg)) == NULL)
1734 return (-1);
1736 if ((inst = scf_instance_create(h)) == NULL ||
1737 (svc = scf_service_create(h)) == NULL ||
1738 (snaplvl = scf_snaplevel_create(h)) == NULL) {
1739 goto fail;
1742 if ((fmribuf = malloc(fbufsz)) == NULL ||
1743 (pg_name = malloc(nbufsz)) == NULL ||
1744 (pg_type = malloc(tbufsz)) == NULL ||
1745 (p = calloc(1, sizeof (pg_tmpl_walk_t))) == NULL) {
1746 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1747 goto fail;
1750 if (scf_pg_get_name(pg, pg_name, nbufsz) < 0) {
1751 goto fail;
1754 if (scf_pg_get_type(pg, pg_type, tbufsz) < 0) {
1755 goto fail;
1757 p->pw_pgname = pg_name;
1758 p->pw_pgtype = pg_type;
1760 ret = scf_pg_get_parent_snaplevel(pg, snaplvl);
1761 if (ret == -1) {
1762 switch (scf_error()) {
1763 case SCF_ERROR_CONSTRAINT_VIOLATED:
1764 /* Parent type doesn't match. Keep looking. */
1765 break;
1767 case SCF_ERROR_DELETED:
1768 case SCF_ERROR_NOT_BOUND:
1769 case SCF_ERROR_NOT_SET:
1770 /* Pass these back to the caller. */
1771 goto fail;
1773 case SCF_ERROR_HANDLE_MISMATCH:
1774 default:
1775 assert(0);
1776 abort();
1780 * No snapshot. We'll use 'editing' by default since
1781 * snap and snapbuf are NULL.
1783 p->pw_snapname = NULL;
1785 } else {
1786 if ((snap = scf_snapshot_create(h)) == NULL) {
1787 goto fail;
1790 ret = scf_snaplevel_get_parent(snaplvl, snap);
1791 if (ret == -1) {
1792 if (ismember(scf_error(), errors_server)) {
1793 goto fail;
1794 } else {
1795 assert(0);
1796 abort();
1800 /* Grab snapshot name while we're here. */
1801 if ((snapbuf = malloc(nbufsz)) == NULL) {
1802 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1803 goto fail;
1805 if (scf_snapshot_get_name(snap, snapbuf, nbufsz) < 0) {
1806 if (ismember(scf_error(), errors_server)) {
1807 goto fail;
1808 } else {
1809 assert(0);
1810 abort();
1813 p->pw_snapname = snapbuf;
1815 ret = scf_snapshot_get_parent(snap, inst);
1816 if (ret == -1) {
1817 if (ismember(scf_error(), errors_server)) {
1818 goto fail;
1819 } else {
1820 assert(0);
1821 abort();
1825 _walk_template_instances(NULL, inst, snap,
1826 (walk_template_inst_func_t *)find_pg_match, p, flags);
1829 /* No snapshot parent. Go looking for instance parent. */
1830 if (snapbuf == NULL) {
1831 /* First look for instance parent. */
1832 ret = scf_pg_get_parent_instance(pg, inst);
1833 if (ret == 0) {
1834 _walk_template_instances(NULL, inst, snap,
1835 (walk_template_inst_func_t *)find_pg_match,
1836 p, flags);
1837 /* OK, check for service parent */
1838 } else if (ret == -1 &&
1839 scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) {
1840 ret = scf_pg_get_parent_service(pg, svc);
1841 if (ret == 0) {
1842 _walk_template_instances(svc, NULL, snap,
1843 (walk_template_inst_func_t *)find_pg_match,
1844 p, flags);
1845 } else {
1846 switch (scf_error()) {
1847 case SCF_ERROR_CONSTRAINT_VIOLATED:
1848 (void) scf_set_error(
1849 SCF_ERROR_NOT_FOUND);
1850 /*FALLTHROUGH*/
1852 case SCF_ERROR_CONNECTION_BROKEN:
1853 case SCF_ERROR_DELETED:
1854 case SCF_ERROR_HANDLE_MISMATCH:
1855 case SCF_ERROR_NOT_BOUND:
1856 case SCF_ERROR_NOT_SET:
1857 goto fail;
1859 default:
1860 assert(0);
1861 abort();
1864 } else {
1865 goto fail;
1869 if (p->pw_pg != NULL) {
1870 pg_tmpl->pt_h = h;
1871 pg_tmpl->pt_pg = p->pw_pg;
1872 pg_tmpl->pt_inst = p->pw_inst;
1873 /* we may get a different instance back */
1874 if (p->pw_inst != inst)
1875 scf_instance_destroy(inst);
1876 pg_tmpl->pt_snap = p->pw_snap;
1877 pg_tmpl->pt_svc = p->pw_svc;
1878 /* we may get a different service back */
1879 if (p->pw_svc != svc)
1880 scf_service_destroy(svc);
1881 pg_tmpl->pt_populated = 1;
1882 free(p->pw_tmpl_pgname);
1883 ret = 0;
1884 goto done;
1887 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
1889 fail:
1890 ret = -1;
1891 scf_instance_destroy(inst);
1892 scf_service_destroy(svc);
1893 done:
1894 scf_snapshot_destroy(snap);
1895 free(snapbuf);
1896 free(fmribuf);
1897 free(pg_name);
1898 free(pg_type);
1899 free(p);
1900 scf_snaplevel_destroy(snaplvl);
1901 return (ret);
1905 * int scf_tmpl_get_by_pg_name()
1907 * Get a template by a combination of the name and type. Either name
1908 * or type can be null, which indicates a wildcard. flags may be
1909 * SCF_PG_TMPL_FLAG_CURRENT (use current properties rather than
1910 * the defined or running snapshot), and SCF_PG_TMPL_FLAG_EXACT (match
1911 * only templates defined by the FMRI in question, not by its restarter
1912 * or globally). Returns 0 on success and -1 on error, and sets
1913 * scf_error() to:
1914 * SCF_ERROR_BACKEND_ACCESS
1915 * SCF_ERROR_CONNECTION_BROKEN
1916 * The connection to the repository was lost.
1917 * SCF_ERROR_DELETED
1918 * The instance has been deleted.
1919 * SCF_ERROR_HANDLE_DESTROYED
1920 * SCF_ERROR_INTERNAL
1921 * SCF_ERROR_INVALID_ARGUMENT
1922 * FMRI isn't valid, pg_name is too long to look for a template, or
1923 * snapshot specified isn't a valid name
1924 * SCF_ERROR_NO_MEMORY
1925 * SCF_ERROR_NO_RESOURCES
1926 * The server does not have adequate resources to complete the request.
1927 * SCF_ERROR_NOT_BOUND
1928 * The handle is not currently bound.
1929 * SCF_ERROR_NOT_FOUND
1930 * Object matching FMRI doesn't exist in the repository, or snapshot
1931 * doesn't exist.
1934 scf_tmpl_get_by_pg_name(const char *fmri, const char *snapshot,
1935 const char *pg_name, const char *pg_type, scf_pg_tmpl_t *pg_tmpl, int flags)
1937 scf_instance_t *inst = NULL;
1938 scf_service_t *svc = NULL;
1939 scf_snapshot_t *snap = NULL;
1940 pg_tmpl_walk_t *p = NULL;
1941 scf_handle_t *h;
1942 int ret;
1944 assert(pg_tmpl != NULL);
1945 h = pg_tmpl->pt_h;
1946 assert(h != NULL);
1948 scf_tmpl_pg_reset(pg_tmpl);
1950 if ((inst = scf_instance_create(h)) == NULL ||
1951 (svc = scf_service_create(h)) == NULL) {
1952 goto fail;
1955 p = calloc(1, sizeof (pg_tmpl_walk_t));
1956 if (p == NULL) {
1957 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1958 goto fail;
1961 ret = scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
1962 NULL, SCF_DECODE_FMRI_EXACT);
1963 if (ret == 0) {
1964 scf_service_destroy(svc);
1965 svc = NULL;
1966 } else if (ret != 0 &&
1967 scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) {
1968 ret = scf_handle_decode_fmri(h, fmri, NULL, svc,
1969 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT);
1970 if (ret == 0) {
1971 scf_instance_destroy(inst);
1972 inst = NULL;
1975 if (ret != 0) {
1976 if (ismember(scf_error(), errors_server)) {
1977 goto fail;
1978 } else switch (scf_error()) {
1979 case SCF_ERROR_CONSTRAINT_VIOLATED:
1980 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1981 goto fail;
1983 case SCF_ERROR_INVALID_ARGUMENT:
1984 case SCF_ERROR_NOT_FOUND:
1985 goto fail;
1987 case SCF_ERROR_HANDLE_MISMATCH:
1988 case SCF_ERROR_NOT_SET:
1989 default:
1990 assert(0);
1991 abort();
1995 assert(svc == NULL || inst == NULL);
1996 assert(svc != NULL || inst != NULL);
1998 /* If we have a service fmri, snapshot is ignored. */
1999 if (inst != NULL) {
2000 if (snapshot == NULL || strcmp(snapshot, "running") == 0 ||
2001 (flags & SCF_PG_TMPL_FLAG_CURRENT) ==
2002 SCF_PG_TMPL_FLAG_CURRENT) {
2003 if (_get_snapshot(inst, NULL, &snap) == -1)
2004 goto fail;
2005 } else {
2006 if (_get_snapshot(inst, snapshot, &snap) == -1) {
2007 goto fail;
2008 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
2009 goto fail;
2014 p->pw_snapname = snapshot;
2015 p->pw_pgname = pg_name;
2016 p->pw_pgtype = pg_type;
2019 * For each of instance, restarter, global
2020 * - check for a tm_pg_pattern_nt_<name> matching type
2021 * - check for a tm_pg_pattern_t_<type> matching type
2022 * - check for any tm_pg_pattern_
2023 * Currently plan to return the most specific match only.
2025 _walk_template_instances(svc, inst, snap,
2026 (walk_template_inst_func_t *)find_pg_match, p, flags);
2028 if (p->pw_pg != NULL) {
2029 pg_tmpl->pt_h = h;
2030 pg_tmpl->pt_pg = p->pw_pg;
2031 pg_tmpl->pt_inst = p->pw_inst;
2032 /* we may get a different instance back */
2033 if (p->pw_inst != inst)
2034 scf_instance_destroy(inst);
2035 pg_tmpl->pt_snap = p->pw_snap;
2036 pg_tmpl->pt_svc = p->pw_svc;
2037 /* we may get a different service back */
2038 if (p->pw_svc != svc)
2039 scf_service_destroy(svc);
2040 pg_tmpl->pt_populated = 1;
2041 scf_snapshot_destroy(snap);
2042 free(p->pw_tmpl_pgname);
2043 free(p);
2044 return (0);
2047 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
2048 fail:
2049 free(p);
2050 scf_instance_destroy(inst);
2051 scf_service_destroy(svc);
2052 scf_snapshot_destroy(snap);
2053 return (-1);
2057 * Returns NULL on failure, sets scf_error() to _CONNECTION_BROKEN,
2058 * _DELETED, _NO_RESOURCES, or _NOT_BOUND.
2060 static scf_iter_t *
2061 _get_svc_or_inst_iter(scf_handle_t *h, scf_pg_tmpl_t *t)
2063 scf_iter_t *iter;
2064 int ret;
2066 assert(t->pt_svc != NULL || t->pt_inst != NULL);
2067 assert(t->pt_svc == NULL || t->pt_inst == NULL);
2069 if ((iter = scf_iter_create(h)) == NULL) {
2070 return (NULL);
2073 /* Iterate on property groups of type template_pg_pattern */
2075 if (t->pt_inst != NULL)
2076 ret = scf_iter_instance_pgs_typed_composed(iter,
2077 t->pt_inst, t->pt_snap,
2078 SCF_GROUP_TEMPLATE_PG_PATTERN);
2079 if (t->pt_svc != NULL)
2080 ret = scf_iter_service_pgs_typed(iter, t->pt_svc,
2081 SCF_GROUP_TEMPLATE_PG_PATTERN);
2083 if (ret != 0) {
2084 if (ismember(scf_error(), errors_server)) {
2085 scf_iter_destroy(iter);
2086 return (NULL);
2087 } else {
2088 assert(0);
2089 abort();
2093 return (iter);
2097 * Returns NULL on failure, sets scf_error() to:
2098 * SCF_ERROR_BACKEND_ACCESS
2099 * SCF_ERROR_CONNECTION_BROKEN
2100 * SCF_ERROR_DELETED
2101 * SCF_HANDLE_DESTROYED
2102 * SCF_ERROR_INTERNAL
2103 * SCF_ERROR_INVALID_ARGUMENT
2104 * Handle argument is NULL, or snaphot is not a valid snapshot name.
2105 * SCF_ERROR_NO_MEMORY
2106 * SCF_ERROR_NO_RESOURCES
2107 * SCF_ERROR_NOT_BOUND
2108 * SCF_ERROR_NOT_FOUND
2110 static scf_iter_t *
2111 _get_next_iterator(scf_handle_t *h, scf_pg_tmpl_t *t, const char *snapshot,
2112 int exact)
2114 scf_iter_t *iter = NULL;
2115 ssize_t limit;
2117 limit = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
2118 assert(limit != 0);
2121 * Check what level we last iterated on: none, service,
2122 * restarter, or global. Make sure that if one in the middle
2123 * doesn't exist, we move on to the next entity.
2125 * Before we drop any references to pt_inst or pt_svc we must
2126 * destroy them so we don't leak them.
2128 do {
2129 switch (t->pt_iter_last) {
2130 case SCF__TMPL_ITER_NONE:
2131 t->pt_iter_last = SCF__TMPL_ITER_INST;
2132 if (t->pt_inst != t->pt_orig_inst)
2133 scf_instance_destroy(t->pt_inst);
2134 t->pt_inst = t->pt_orig_inst;
2135 if (t->pt_svc != t->pt_orig_svc)
2136 scf_service_destroy(t->pt_svc);
2137 t->pt_svc = t->pt_orig_svc;
2138 break;
2140 case SCF__TMPL_ITER_INST:
2142 * Don't go any further than the specified instance
2143 * if exact was set.
2145 if (exact == 1) {
2146 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
2147 goto fail;
2149 t->pt_iter_last = SCF__TMPL_ITER_RESTARTER;
2150 if (t->pt_inst != t->pt_orig_inst)
2151 scf_instance_destroy(t->pt_inst);
2152 t->pt_inst = _get_restarter_inst(h, t->pt_orig_svc,
2153 t->pt_orig_inst, t->pt_snap);
2154 if (t->pt_svc != t->pt_orig_svc)
2155 scf_service_destroy(t->pt_svc);
2156 t->pt_svc = NULL;
2157 break;
2159 case SCF__TMPL_ITER_RESTARTER:
2160 t->pt_iter_last = SCF__TMPL_ITER_GLOBAL;
2161 if (t->pt_inst != t->pt_orig_inst)
2162 scf_instance_destroy(t->pt_inst);
2163 t->pt_inst = _get_global_inst(h);
2164 if (t->pt_svc != t->pt_orig_svc)
2165 scf_service_destroy(t->pt_svc);
2166 t->pt_svc = NULL;
2167 break;
2169 case SCF__TMPL_ITER_GLOBAL:
2170 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
2171 return (NULL);
2173 default:
2174 assert(0);
2175 abort();
2177 } while (t->pt_inst == NULL && t->pt_svc == NULL);
2179 /* Set pt_snap to the snapshot for this instance */
2180 if (t->pt_inst != NULL) {
2181 scf_snapshot_destroy(t->pt_snap);
2182 if (_get_snapshot(t->pt_inst, snapshot,
2183 &t->pt_snap) == -1)
2184 goto fail;
2187 iter = _get_svc_or_inst_iter(h, t);
2188 fail:
2189 return (iter);
2193 * scf_pg_tmpl_t *scf_tmpl_pg_create(scf_handle_t *)
2195 * Returns NULL on failure, sets scf_error() to _INVALID_ARGUMENT
2196 * or _NO_MEMORY.
2198 scf_pg_tmpl_t *
2199 scf_tmpl_pg_create(scf_handle_t *handle)
2201 scf_pg_tmpl_t *pg_tmpl = NULL;
2203 if (handle == NULL) {
2204 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
2205 return (NULL);
2207 pg_tmpl = calloc(1, sizeof (scf_pg_tmpl_t));
2208 if (pg_tmpl == NULL)
2209 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
2210 else
2211 pg_tmpl->pt_h = handle;
2213 return (pg_tmpl);
2217 * Retrieves name or type of a template pg.
2218 * Returns -1 on failure. Sets scf_error():
2219 * SCF_ERROR_BACKEND_ACCESS
2220 * SCF_ERROR_CONNECTION_BROKEN
2221 * SCF_ERROR_DELETED
2222 * SCF_ERROR_HANDLE_DESTROYED
2223 * SCF_ERROR_INTERNAL
2224 * SCF_ERROR_NO_MEMORY
2225 * SCF_ERROR_NO_RESOURCES
2226 * SCF_ERROR_NOT_BOUND
2227 * SCF_ERROR_PERMISSION_DENIED
2228 * SCF_ERROR_TEMPLATE_INVALID
2229 * pname property is not SCF_TYPE_ASTRING or has more than one value.
2231 static ssize_t
2232 _scf_tmpl_prop_value(scf_propertygroup_t *pg, const char *pname, char **out)
2234 assert(strcmp(pname, SCF_PROPERTY_TM_NAME) == 0 ||
2235 strcmp(pname, SCF_PROPERTY_TM_TYPE) == 0);
2237 *out = _scf_read_single_astring_from_pg(pg, pname);
2239 if (*out != NULL && *out[0] == '\0') {
2240 (void) scf_set_error(SCF_ERROR_NONE);
2241 free(*out);
2242 *out = strdup(SCF_TMPL_WILDCARD);
2243 if (*out == NULL)
2244 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
2246 if (*out == NULL) {
2247 if (ismember(scf_error(), errors_server)) {
2248 return (-1);
2249 } else switch (scf_error()) {
2250 case SCF_ERROR_CONSTRAINT_VIOLATED:
2251 case SCF_ERROR_NOT_FOUND:
2252 case SCF_ERROR_TYPE_MISMATCH:
2253 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
2254 return (-1);
2256 case SCF_ERROR_INVALID_ARGUMENT:
2257 case SCF_ERROR_NOT_SET:
2258 default:
2259 assert(0);
2260 abort();
2264 return (strlen(*out));
2268 * int scf_tmpl_iter_pgs()
2270 * Iterates through the property group templates for the fmri given.
2271 * When t is uninitialized or reset, sets t to the first property group
2272 * template in fmri. On subsequent calls, sets t to the next property group
2273 * template in frmi.
2274 * Returns 1 on success, 0 when no property group templates are left to
2275 * iterate, -1 on error.
2276 * The flags argument may include SCF_PG_TMPL_FLAG_REQUIRED,
2277 * SCF_PG_TMPL_FLAG_CURRENT, and/or SCF_PG_TMPL_FLAG_EXACT.
2279 * Returns -1 on error and sets scf_error() to:
2280 * SCF_ERROR_BACKEND_ACCESS
2281 * SCF_ERROR_CONNECTION_BROKEN
2282 * SCF_ERROR_DELETED
2283 * SCF_ERROR_HANDLE_DESTROYED
2284 * SCF_ERROR_INTERNAL
2285 * SCF_ERROR_INVALID_ARGUMENT
2286 * The handle argument is NULL, fmri is invalid, or snapshot is invalid.
2287 * SCF_ERROR_NO_MEMORY
2288 * SCF_ERROR_NO_RESOURCES
2289 * SCF_ERROR_NOT_BOUND
2290 * SCF_ERROR_NOT_FOUND
2291 * SCF_ERROR_PERMISSION_DENIED
2294 scf_tmpl_iter_pgs(scf_pg_tmpl_t *t, const char *fmri, const char *snapshot,
2295 const char *type, int flags)
2297 scf_handle_t *h;
2298 scf_service_t *svc = NULL;
2299 scf_instance_t *inst = NULL;
2300 scf_propertygroup_t *pg = NULL;
2301 scf_snapshot_t *snap = NULL;
2302 scf_pg_tmpl_t *pg_tmpl = NULL;
2303 int err;
2304 int found = 0;
2305 char *tmpl_type;
2306 uint8_t required;
2307 int ret;
2309 if (t == NULL) {
2310 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
2311 return (-1);
2314 h = t->pt_h;
2316 if (t->pt_populated == 0) {
2317 if ((svc = scf_service_create(h)) == NULL ||
2318 (inst = scf_instance_create(h)) == NULL ||
2319 (pg = scf_pg_create(h)) == NULL) {
2320 goto fail_non_populated;
2323 ret = scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
2324 NULL, SCF_DECODE_FMRI_EXACT);
2325 if (ret == 0) {
2326 scf_service_destroy(svc);
2327 svc = NULL;
2328 } else if (ret != 0 &&
2329 scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) {
2330 ret = scf_handle_decode_fmri(h, fmri, NULL, svc,
2331 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT);
2332 if (ret == 0) {
2333 scf_instance_destroy(inst);
2334 inst = NULL;
2338 if (ret != 0) {
2339 if (ismember(scf_error(), errors_server)) {
2340 goto fail_non_populated;
2341 } else switch (scf_error()) {
2342 case SCF_ERROR_CONSTRAINT_VIOLATED:
2343 (void) scf_set_error(
2344 SCF_ERROR_INVALID_ARGUMENT);
2345 goto fail_non_populated;
2347 case SCF_ERROR_INVALID_ARGUMENT:
2348 case SCF_ERROR_NOT_FOUND:
2349 goto fail_non_populated;
2351 case SCF_ERROR_HANDLE_MISMATCH:
2352 case SCF_ERROR_NOT_SET:
2353 default:
2354 assert(0);
2355 abort();
2359 assert(svc == NULL || inst == NULL);
2360 assert(svc != NULL || inst != NULL);
2362 if (inst != NULL) {
2363 if (snapshot == NULL ||
2364 strcmp(snapshot, "running") == 0 ||
2365 (flags & SCF_PG_TMPL_FLAG_CURRENT) ==
2366 SCF_PG_TMPL_FLAG_CURRENT) {
2367 if (_get_snapshot(inst, NULL, &snap) == -1)
2368 goto fail_non_populated;
2369 } else {
2370 (void) scf_set_error(SCF_ERROR_NONE);
2371 if (_get_snapshot(inst, snapshot,
2372 &snap) == -1) {
2373 goto fail_non_populated;
2374 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
2375 goto fail_non_populated;
2378 } else {
2379 scf_snapshot_destroy(snap);
2380 snap = NULL;
2383 pg_tmpl = t;
2384 pg_tmpl->pt_orig_inst = inst;
2385 pg_tmpl->pt_orig_svc = svc;
2386 pg_tmpl->pt_snap = snap;
2387 pg_tmpl->pt_is_iter = 1;
2388 pg_tmpl->pt_iter_last = SCF__TMPL_ITER_NONE;
2389 pg_tmpl->pt_pg = pg;
2390 pg_tmpl->pt_populated = 1;
2391 } else {
2392 if (t->pt_is_iter != 1) {
2393 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
2394 return (-1);
2396 pg_tmpl = t;
2397 assert(pg_tmpl->pt_pg != NULL);
2400 if (pg_tmpl->pt_iter == NULL) {
2401 pg_tmpl->pt_iter = _get_next_iterator(h, pg_tmpl, snapshot,
2402 (flags & SCF_PG_TMPL_FLAG_EXACT) ? 1 : 0);
2403 if (pg_tmpl->pt_iter == NULL) {
2404 if (scf_error() == SCF_ERROR_NOT_FOUND)
2405 return (0);
2406 else
2407 return (-1);
2411 while (found == 0) {
2412 while ((err = scf_iter_next_pg(pg_tmpl->pt_iter,
2413 pg_tmpl->pt_pg)) != 1) {
2414 if (err == -1) {
2415 if (ismember(scf_error(), errors_server)) {
2416 return (-1);
2417 } else switch (scf_error()) {
2418 case SCF_ERROR_HANDLE_MISMATCH:
2419 return (-1);
2421 case SCF_ERROR_NOT_SET:
2422 case SCF_ERROR_INVALID_ARGUMENT:
2423 default:
2424 assert(0);
2425 abort();
2427 } else if (err == 0) {
2428 /* This iteration is done. Get the next one */
2429 scf_iter_destroy(pg_tmpl->pt_iter);
2430 pg_tmpl->pt_iter = _get_next_iterator(h,
2431 pg_tmpl, snapshot,
2432 (flags & SCF_PG_TMPL_FLAG_EXACT) ? 1 : 0);
2433 if (pg_tmpl->pt_iter == NULL) {
2434 if (scf_error() == SCF_ERROR_NOT_FOUND)
2435 return (0);
2436 else
2437 return (-1);
2439 continue;
2440 } else {
2441 assert(0);
2442 abort();
2447 * Discard pgs which don't exist at the right scoping. This
2448 * check also makes sure that if we're looking at, for
2449 * example, svc:/system/svc/restarter:default, that we
2450 * don't hand back the same property groups twice.
2452 switch (t->pt_iter_last) {
2453 case SCF__TMPL_ITER_INST:
2454 ret = check_target_match(pg_tmpl->pt_pg,
2455 SCF_TM_TARGET_THIS);
2456 break;
2457 case SCF__TMPL_ITER_RESTARTER:
2458 ret = check_target_match(pg_tmpl->pt_pg,
2459 SCF_TM_TARGET_DELEGATE);
2460 break;
2461 case SCF__TMPL_ITER_GLOBAL:
2462 ret = check_target_match(pg_tmpl->pt_pg,
2463 SCF_TM_TARGET_ALL);
2464 break;
2465 case SCF__TMPL_ITER_NONE:
2466 default:
2467 assert(0);
2468 abort();
2471 if (ret != 0)
2472 continue;
2475 * If walking only required property groups, check if
2476 * the retrieved group is required.
2478 if (flags & SCF_PG_TMPL_FLAG_REQUIRED) {
2479 if (scf_tmpl_pg_required(pg_tmpl, &required) == 0) {
2480 if (required == 0)
2481 continue;
2482 } else {
2483 return (-1);
2488 * If type != NULL, check if type property matches. If no
2489 * type property exists, consider it a match.
2491 if (type != NULL) {
2492 if (scf_tmpl_pg_type(pg_tmpl, &tmpl_type) != -1) {
2493 if (strcmp(tmpl_type, SCF_TMPL_WILDCARD)
2494 == 0 || strcmp(type, tmpl_type) == 0) {
2495 free(tmpl_type);
2496 break;
2498 free(tmpl_type);
2499 } else if (scf_error() == SCF_ERROR_NOT_FOUND ||
2500 scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED ||
2501 scf_error() == SCF_ERROR_TYPE_MISMATCH) {
2502 break;
2503 } else {
2504 return (-1);
2506 } else {
2507 break;
2511 return (1);
2513 fail_non_populated:
2514 scf_service_destroy(svc);
2515 scf_instance_destroy(inst);
2516 scf_pg_destroy(pg);
2517 scf_snapshot_destroy(snap);
2518 return (-1);
2521 void
2522 scf_tmpl_pg_destroy(scf_pg_tmpl_t *t)
2524 if (t == NULL)
2525 return;
2527 scf_pg_destroy(t->pt_pg);
2528 scf_instance_destroy(t->pt_inst);
2529 if (t->pt_inst != t->pt_orig_inst)
2530 scf_instance_destroy(t->pt_orig_inst);
2531 scf_snapshot_destroy(t->pt_snap);
2532 scf_service_destroy(t->pt_orig_svc);
2533 if (t->pt_svc != t->pt_orig_svc)
2534 scf_service_destroy(t->pt_svc);
2535 scf_iter_destroy(t->pt_iter);
2536 free(t);
2539 void
2540 scf_tmpl_pg_reset(scf_pg_tmpl_t *t)
2542 scf_pg_destroy(t->pt_pg);
2543 t->pt_pg = NULL;
2545 scf_instance_destroy(t->pt_inst);
2546 if (t->pt_inst != t->pt_orig_inst)
2547 scf_instance_destroy(t->pt_orig_inst);
2548 t->pt_inst = NULL;
2549 t->pt_orig_inst = NULL;
2551 scf_snapshot_destroy(t->pt_snap);
2552 t->pt_snap = NULL;
2554 scf_service_destroy(t->pt_orig_svc);
2555 if (t->pt_svc != t->pt_orig_svc)
2556 scf_service_destroy(t->pt_svc);
2557 t->pt_orig_svc = NULL;
2558 t->pt_svc = NULL;
2560 scf_iter_destroy(t->pt_iter);
2561 t->pt_iter = NULL;
2563 t->pt_populated = 0;
2564 t->pt_is_iter = 0;
2565 t->pt_iter_last = 0;
2567 /* Do not reset t->pt_h. */
2571 * int scf_tmpl_get_by_prop()
2573 * Get the property template given a property group template and property
2574 * name. No flags are currently defined for this function.
2576 * Returns NULL on failure, and sets scf_error():
2577 * SCF_ERROR_BACKEND_ACCESS
2578 * SCF_ERROR_CONNECTION_BROKEN
2579 * SCF_ERROR_DELETED
2580 * SCF_ERROR_HANDLE_DESTROYED
2581 * SCF_ERROR_INTERNAL
2582 * SCF_ERROR_INVALID_ARGUMENT
2583 * SCF_ERROR_NO_MEMORY
2584 * SCF_ERROR_NO_RESOURCES
2585 * SCF_ERROR_NOT_BOUND
2586 * SCF_ERROR_NOT_FOUND
2587 * Template object matching property doesn't exist in the repository.
2588 * SCF_ERROR_TYPE_MISMATCH
2589 * Matching template object is the wrong type in the repository.
2592 scf_tmpl_get_by_prop(scf_pg_tmpl_t *t, const char *prop,
2593 scf_prop_tmpl_t *prop_tmpl, int flags)
2595 char *tmpl_prop_name;
2596 scf_propertygroup_t *pg = NULL;
2597 char *pg_type;
2598 int found = 0;
2600 if (flags != 0) {
2601 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
2602 return (-1);
2605 scf_tmpl_prop_reset(prop_tmpl);
2606 if ((pg = scf_pg_create(scf_pg_handle(t->pt_pg))) == NULL)
2607 return (-1);
2609 tmpl_prop_name = _tmpl_prop_name(prop, t);
2610 if (tmpl_prop_name == NULL) {
2611 assert(scf_error() != SCF_ERROR_NOT_SET);
2612 return (-1);
2615 if (_get_pg(t->pt_svc, t->pt_inst, t->pt_snap,
2616 tmpl_prop_name, pg) != 0) {
2617 if (!ismember(scf_error(), errors_server)) {
2618 switch (scf_error()) {
2619 case SCF_ERROR_NOT_FOUND:
2620 case SCF_ERROR_INVALID_ARGUMENT:
2621 break;
2623 case SCF_ERROR_NOT_SET:
2624 case SCF_ERROR_HANDLE_MISMATCH:
2625 default:
2626 assert(0);
2627 abort();
2630 } else {
2632 * We've only found a template property group if the type
2633 * is correct.
2635 if ((pg_type = _scf_get_pg_type(pg)) != NULL &&
2636 strcmp(pg_type, SCF_GROUP_TEMPLATE_PROP_PATTERN) == 0)
2637 found++;
2638 else
2639 (void) scf_set_error(SCF_ERROR_TYPE_MISMATCH);
2642 free(pg_type);
2645 if (found == 0) {
2646 scf_pg_destroy(pg);
2647 free(tmpl_prop_name);
2648 return (-1);
2651 prop_tmpl->prt_h = scf_pg_handle(t->pt_pg);
2652 prop_tmpl->prt_t = t;
2653 prop_tmpl->prt_pg = pg;
2654 prop_tmpl->prt_pg_name = tmpl_prop_name;
2655 prop_tmpl->prt_populated = 1;
2657 return (0);
2661 * scf_prop_tmpl_t *scf_tmpl_prop_create(scf_handle_t *);
2663 * Returns NULL on failure, sets scf_error() to _INVALID_ARGUMENT, or
2664 * _NO_MEMORY.
2666 scf_prop_tmpl_t *
2667 scf_tmpl_prop_create(scf_handle_t *handle)
2669 scf_prop_tmpl_t *pt;
2671 if (handle == NULL) {
2672 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
2673 return (NULL);
2675 pt = calloc(1, sizeof (scf_prop_tmpl_t));
2676 if (pt == NULL)
2677 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
2678 else
2679 pt->prt_h = handle;
2681 return (pt);
2685 * int scf_tmpl_iter_props()
2687 * Iterates over all property templates defined in the specified property
2688 * group template. The iterator state is stored on the property template
2689 * data structure, and the data structure should be allocated with
2690 * scf_tmpl_prop_create(). To continue the iteration, the previously
2691 * returned structure should be passed in as an argument to this function.
2692 * flags can include SCF_PROP_TMPL_FLAG_REQUIRED. The function returns
2693 * 1 when a result was found, and 0 when the iteration is complete.
2695 * Returns -1 on failure, and sets scf_error():
2696 * SCF_ERROR_BACKEND_ACCESS
2697 * SCF_ERROR_CONNECTION_BROKEN
2698 * SCF_ERROR_DELETED
2699 * SCF_ERROR_HANDLE_DESTROYED
2700 * SCF_ERROR_INTERNAL
2701 * SCF_ERROR_INVALID_ARGUMENT
2702 * SCF_ERROR_NO_MEMORY
2703 * SCF_ERROR_NO_RESOURCES
2704 * SCF_ERROR_NOT_BOUND
2705 * SCF_ERROR_PERMISSION_DENIED
2706 * SCF_ERROR_TEMPLATE_INVALID
2707 * Template data is invalid. One of the property templates in this
2708 * pg_tmpl is malformed.
2711 scf_tmpl_iter_props(scf_pg_tmpl_t *t, scf_prop_tmpl_t *pt, int flags)
2713 scf_prop_tmpl_t *prop_tmpl;
2714 char *pg_pat;
2715 char *pg_name = NULL;
2716 int err;
2717 int ret;
2718 ssize_t size = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
2719 uint8_t required;
2720 scf_handle_t *h;
2721 scf_propertygroup_t *pg = NULL;
2722 scf_iter_t *iter = NULL;
2724 assert(size != 0);
2725 if (t == NULL || pt == NULL) {
2726 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
2727 return (-1);
2730 assert(t->pt_inst == NULL || t->pt_svc == NULL);
2731 assert(t->pt_inst != NULL || t->pt_svc != NULL);
2733 if ((pg_name = malloc(size)) == NULL) {
2734 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
2735 return (-1);
2738 if (pt->prt_populated == 0) {
2739 if ((h = scf_pg_handle(t->pt_pg)) == NULL)
2740 goto fail_non_populated;
2742 if ((pg = scf_pg_create(h)) == NULL ||
2743 (iter = scf_iter_create(h)) == NULL)
2744 goto fail_non_populated;
2746 if (t->pt_inst != NULL)
2747 err = scf_iter_instance_pgs_typed_composed(iter,
2748 t->pt_inst, t->pt_snap,
2749 SCF_GROUP_TEMPLATE_PROP_PATTERN);
2750 else if (t->pt_svc != NULL)
2751 err = scf_iter_service_pgs_typed(iter, t->pt_svc,
2752 SCF_GROUP_TEMPLATE_PROP_PATTERN);
2754 if (err != 0) {
2755 if (ismember(scf_error(), errors_server)) {
2756 goto fail_non_populated;
2757 } else switch (scf_error()) {
2758 case SCF_ERROR_INVALID_ARGUMENT:
2759 goto fail_non_populated;
2761 case SCF_ERROR_NOT_SET:
2762 case SCF_ERROR_HANDLE_MISMATCH:
2763 default:
2764 assert(0);
2765 abort();
2769 prop_tmpl = pt;
2770 prop_tmpl->prt_t = t;
2771 prop_tmpl->prt_populated = 1;
2772 prop_tmpl->prt_pg = pg;
2773 prop_tmpl->prt_iter = iter;
2774 } else {
2775 prop_tmpl = pt;
2778 while ((err = scf_iter_next_pg(prop_tmpl->prt_iter,
2779 prop_tmpl->prt_pg)) > 0) {
2781 * Check if the name matches the appropriate property
2782 * group template name.
2784 pg_pat = _scf_read_single_astring_from_pg(prop_tmpl->prt_pg,
2785 SCF_PROPERTY_TM_PG_PATTERN);
2786 if (pg_pat == NULL) {
2787 if (ismember(scf_error(), errors_server)) {
2788 uu_free(pg_name);
2789 return (-1);
2790 } else switch (scf_error()) {
2791 case SCF_ERROR_NOT_FOUND:
2792 continue;
2794 case SCF_ERROR_CONSTRAINT_VIOLATED:
2795 case SCF_ERROR_TYPE_MISMATCH:
2796 (void) scf_set_error(
2797 SCF_ERROR_TEMPLATE_INVALID);
2798 free(pg_name);
2799 return (-1);
2801 case SCF_ERROR_INVALID_ARGUMENT:
2802 case SCF_ERROR_NOT_SET:
2803 default:
2804 assert(0);
2805 abort();
2808 if ((ret = scf_pg_get_name(t->pt_pg, pg_name, size)) <= 0) {
2809 free(pg_pat);
2810 if (ret == 0)
2811 continue;
2813 if (ismember(scf_error(), errors_server)) {
2814 free(pg_name);
2815 return (-1);
2816 } else {
2817 assert(0);
2818 abort();
2821 if (strcmp(pg_pat, pg_name) != 0) {
2822 free(pg_pat);
2823 continue;
2825 free(pg_pat);
2828 * If walking only required properties, check if
2829 * the retrieved property is required.
2831 if (flags & SCF_PROP_TMPL_FLAG_REQUIRED) {
2832 if (scf_tmpl_prop_required(prop_tmpl, &required) == 0) {
2833 if (required == 0)
2834 continue;
2835 } else {
2836 free(pg_name);
2837 return (-1);
2840 free(pg_name);
2841 return (0);
2844 if (err == -1) {
2845 if (ismember(scf_error(), errors_server)) {
2846 free(pg_name);
2847 return (-1);
2848 } else {
2849 assert(0);
2850 abort();
2852 } else if (err == 0) {
2853 scf_iter_destroy(prop_tmpl->prt_iter);
2854 prop_tmpl->prt_iter = NULL;
2855 prop_tmpl->prt_populated = 0;
2857 free(pg_name);
2859 return (1);
2861 fail_non_populated:
2862 free(pg_name);
2863 scf_pg_destroy(pg);
2864 scf_iter_destroy(iter);
2865 return (-1);
2868 void
2869 scf_tmpl_prop_destroy(scf_prop_tmpl_t *t)
2871 if (t == NULL)
2872 return;
2874 scf_pg_destroy(t->prt_pg);
2875 free(t->prt_pg_name);
2876 free(t->prt_iter);
2877 free(t);
2880 void
2881 scf_tmpl_prop_reset(scf_prop_tmpl_t *t)
2883 scf_pg_destroy(t->prt_pg);
2884 t->prt_pg = NULL;
2886 free(t->prt_pg_name);
2887 t->prt_pg_name = NULL;
2889 free(t->prt_iter);
2890 t->prt_iter = NULL;
2892 t->prt_populated = 0;
2893 t->prt_h = NULL;
2894 t->prt_t = NULL;
2898 * Returns -1 on failure. Sets scf_error():
2899 * SCF_ERROR_BACKEND_ACCESS
2900 * SCF_ERROR_CONNECTION_BROKEN
2901 * SCF_ERROR_DELETED
2902 * SCF_ERROR_HANDLE_DESTROYED
2903 * SCF_ERROR_INTERNAL
2904 * SCF_ERROR_NO_MEMORY
2905 * SCF_ERROR_NO_RESOURCES
2906 * SCF_ERROR_NOT_BOUND
2907 * SCF_ERROR_PERMISSION_DENIED
2908 * SCF_ERROR_TEMPLATE_INVALID
2909 * The name of the template property group (the pname property) has
2910 * an improper repository format and is not type astring or has
2911 * more than one value.
2913 ssize_t
2914 scf_tmpl_pg_name(const scf_pg_tmpl_t *t, char **out)
2916 return (_scf_tmpl_prop_value(t->pt_pg, SCF_PROPERTY_TM_NAME, out));
2920 * returns an allocated string that must be freed
2922 * Returns NULL on failure, sets scf_error() to:
2923 * SCF_ERROR_BACKEND_ACCESS
2924 * SCF_ERROR_CONNECTION_BROKEN
2925 * SCF_ERROR_DELETED
2926 * SCF_ERROR_HANDLE_DESTROYED
2927 * SCF_ERROR_INTERNAL
2928 * SCF_ERROR_INVALID_ARGUMENT
2929 * name not a valid property name
2930 * name and locale are too long to make a property name
2931 * SCF_ERROR_NO_MEMORY
2932 * SCF_ERROR_NO_RESOURCES
2933 * SCF_ERROR_NOT_BOUND
2934 * SCF_ERROR_NOT_FOUND
2935 * Property doesn't exist or exists and has no value.
2936 * SCF_ERROR_PERMISSION_DENIED
2937 * SCF_ERROR_TEMPLATE_INVALID
2939 static char *
2940 _read_localized_astring_from_pg(scf_propertygroup_t *pg, const char *name,
2941 const char *locale)
2943 char *str;
2944 char *lname_prop;
2946 str = _add_locale_to_name(name, locale);
2947 if (str == NULL)
2948 return (NULL);
2949 lname_prop = _scf_read_single_astring_from_pg(pg, str);
2950 if (lname_prop == NULL) {
2951 free(str);
2952 if (scf_error() != SCF_ERROR_NOT_FOUND)
2953 return (NULL);
2954 str = _add_locale_to_name(name, "C");
2955 if (str == NULL)
2956 return (NULL);
2957 lname_prop = _scf_read_single_astring_from_pg(pg, str);
2959 free(str);
2960 if (lname_prop == NULL) {
2961 if (scf_error() == SCF_ERROR_TYPE_MISMATCH ||
2962 scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED)
2963 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
2965 return (lname_prop);
2969 * returns an allocated string that must be freed
2971 * Returns -1 on failure, sets scf_error() to:
2972 * SCF_ERROR_BACKEND_ACCESS
2973 * SCF_ERROR_CONNECTION_BROKEN
2974 * SCF_ERROR_DELETED
2975 * SCF_ERROR_HANDLE_DESTROYED
2976 * SCF_ERROR_INTERNAL
2977 * SCF_ERROR_INVALID_ARGUMENT
2978 * locale is too long to make a valid property name
2979 * SCF_ERROR_NO_MEMORY
2980 * SCF_ERROR_NO_RESOURCES
2981 * SCF_ERROR_NOT_BOUND
2982 * SCF_ERROR_NOT_FOUND
2983 * Property doesn't exist or exists and has no value.
2984 * SCF_ERROR_PERMISSION_DENIED
2985 * SCF_ERROR_TEMPLATE_INVALID
2987 ssize_t
2988 scf_tmpl_pg_common_name(const scf_pg_tmpl_t *t, const char *locale, char **out)
2990 assert(out != NULL);
2991 if ((*out = _read_localized_astring_from_pg(t->pt_pg,
2992 SCF_PROPERTY_TM_COMMON_NAME_PREFIX, locale)) == NULL)
2993 return (-1);
2995 return (strlen(*out));
2999 * returns an allocated string that must be freed
3001 * Returns -1 on failure, sets scf_error() to:
3002 * SCF_ERROR_BACKEND_ACCESS
3003 * SCF_ERROR_CONNECTION_BROKEN
3004 * SCF_ERROR_DELETED
3005 * SCF_ERROR_HANDLE_DESTROYED
3006 * SCF_ERROR_INTERNAL
3007 * SCF_ERROR_INVALID_ARGUMENT
3008 * locale is too long to make a valid property name
3009 * SCF_ERROR_NO_MEMORY
3010 * SCF_ERROR_NO_RESOURCES
3011 * SCF_ERROR_NOT_BOUND
3012 * SCF_ERROR_NOT_FOUND
3013 * Property doesn't exist or exists and has no value.
3014 * SCF_ERROR_PERMISSION_DENIED
3015 * SCF_ERROR_TEMPLATE_INVALID
3017 ssize_t
3018 scf_tmpl_pg_description(const scf_pg_tmpl_t *t, const char *locale, char **out)
3020 assert(out != NULL);
3021 if ((*out = _read_localized_astring_from_pg(t->pt_pg,
3022 SCF_PROPERTY_TM_DESCRIPTION_PREFIX, locale)) == NULL)
3023 return (-1);
3025 return (strlen(*out));
3029 * Returns -1 on failure. Sets scf_error():
3030 * SCF_ERROR_BACKEND_ACCESS
3031 * SCF_ERROR_CONNECTION_BROKEN
3032 * SCF_ERROR_DELETED
3033 * SCF_ERROR_HANDLE_DESTROYED
3034 * SCF_ERROR_INTERNAL
3035 * SCF_ERROR_NO_MEMORY
3036 * SCF_ERROR_NO_RESOURCES
3037 * SCF_ERROR_NOT_BOUND
3038 * SCF_ERROR_NOT_FOUND
3039 * 'type' property doesn't exist or exists and has no value.
3040 * SCF_ERROR_PERMISSION_DENIED
3041 * SCF_ERROR_TEMPLATE_INVALID
3042 * 'type' property is not SCF_TYPE_ASTRING or has more than one value.
3044 ssize_t
3045 scf_tmpl_pg_type(const scf_pg_tmpl_t *t, char **out)
3047 return (_scf_tmpl_prop_value(t->pt_pg, SCF_PROPERTY_TM_TYPE, out));
3051 * Returns -1 on failure, sets scf_error() to:
3052 * SCF_ERROR_BACKEND_ACCESS
3053 * SCF_ERROR_CONNECTION_BROKEN
3054 * SCF_ERROR_DELETED
3055 * SCF_ERROR_HANDLE_DESTROYED
3056 * SCF_ERROR_INTERNAL
3057 * SCF_ERROR_NO_MEMORY
3058 * SCF_ERROR_NO_RESOURCES
3059 * SCF_ERROR_NOT_BOUND
3060 * SCF_ERROR_PERMISSION_DENIED
3061 * SCF_ERROR_TEMPLATE_INVALID
3062 * required property is not SCF_TYPE_BOOLEAN or has more than one value.
3065 scf_tmpl_pg_required(const scf_pg_tmpl_t *t, uint8_t *out)
3068 if (_read_single_boolean_from_pg(t->pt_pg, SCF_PROPERTY_TM_REQUIRED,
3069 out) == -1) {
3070 if (ismember(scf_error(), errors_server)) {
3071 return (-1);
3072 } else switch (scf_error()) {
3073 case SCF_ERROR_CONSTRAINT_VIOLATED:
3074 case SCF_ERROR_TYPE_MISMATCH:
3075 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
3076 return (-1);
3078 case SCF_ERROR_NOT_FOUND:
3079 *out = 0;
3080 return (0);
3082 case SCF_ERROR_INVALID_ARGUMENT:
3083 default:
3084 assert(0);
3085 abort();
3089 return (0);
3093 * Returns -1 on failure. Sets scf_error():
3094 * SCF_ERROR_BACKEND_ACCESS
3095 * SCF_ERROR_CONNECTION_BROKEN
3096 * SCF_ERROR_DELETED
3097 * SCF_ERROR_HANDLE_DESTROYED
3098 * SCF_ERROR_INTERNAL
3099 * SCF_ERROR_NO_MEMORY
3100 * SCF_ERROR_NO_RESOURCES
3101 * SCF_ERROR_NOT_BOUND
3102 * SCF_ERROR_PERMISSION_DENIED
3103 * SCF_ERROR_TEMPLATE_INVALID
3104 * target property is not SCF_TYPE_ASTRING or has more than one value.
3106 ssize_t
3107 scf_tmpl_pg_target(const scf_pg_tmpl_t *t, char **out)
3109 *out = _scf_read_single_astring_from_pg(t->pt_pg,
3110 SCF_PROPERTY_TM_TARGET);
3112 if (*out == NULL) {
3113 if (ismember(scf_error(), errors_server)) {
3114 return (-1);
3115 } else switch (scf_error()) {
3116 case SCF_ERROR_CONSTRAINT_VIOLATED:
3117 case SCF_ERROR_NOT_FOUND:
3118 case SCF_ERROR_TYPE_MISMATCH:
3119 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
3120 return (-1);
3122 case SCF_ERROR_INVALID_ARGUMENT:
3123 case SCF_ERROR_NOT_SET:
3124 default:
3125 assert(0);
3126 abort();
3130 return (strlen(*out));
3134 * Returns -1 on failure. Sets scf_error():
3135 * SCF_ERROR_BACKEND_ACCESS
3136 * SCF_ERROR_CONNECTION_BROKEN
3137 * SCF_ERROR_DELETED
3138 * SCF_ERROR_HANDLE_DESTROYED
3139 * SCF_ERROR_INTERNAL
3140 * SCF_ERROR_NO_MEMORY
3141 * SCF_ERROR_NO_RESOURCES
3142 * SCF_ERROR_NOT_BOUND
3143 * SCF_ERROR_PERMISSION_DENIED
3144 * SCF_ERROR_TEMPLATE_INVALID
3146 ssize_t
3147 scf_tmpl_prop_name(const scf_prop_tmpl_t *t, char **out)
3149 *out = _scf_read_single_astring_from_pg(t->prt_pg,
3150 SCF_PROPERTY_TM_NAME);
3152 if (*out != NULL && *out[0] == '\0') {
3153 free(*out);
3154 *out = NULL;
3155 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
3157 if (*out == NULL) {
3158 if (ismember(scf_error(), errors_server)) {
3159 return (-1);
3160 } else switch (scf_error()) {
3161 case SCF_ERROR_CONSTRAINT_VIOLATED:
3162 case SCF_ERROR_NOT_FOUND:
3163 case SCF_ERROR_TEMPLATE_INVALID:
3164 case SCF_ERROR_TYPE_MISMATCH:
3165 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
3166 return (-1);
3168 case SCF_ERROR_INVALID_ARGUMENT:
3169 case SCF_ERROR_NOT_SET:
3170 default:
3171 assert(0);
3172 abort();
3176 return (strlen(*out));
3180 * Returns -1 on failure. Sets scf_error():
3181 * SCF_ERROR_BACKEND_ACCESS
3182 * SCF_ERROR_CONNECTION_BROKEN
3183 * SCF_ERROR_DELETED
3184 * SCF_ERROR_HANDLE_DESTROYED
3185 * SCF_ERROR_INTERNAL
3186 * SCF_ERROR_NO_MEMORY
3187 * SCF_ERROR_NO_RESOURCES
3188 * SCF_ERROR_NOT_BOUND
3189 * SCF_ERROR_NOT_FOUND
3190 * 'type' property doesn't exist or exists and has no value.
3191 * SCF_ERROR_PERMISSION_DENIED
3192 * SCF_ERROR_TEMPLATE_INVALID
3193 * 'type' property is not SCF_TYPE_ASTRING, has more than one value,
3194 * is SCF_TYPE_INVALID, or is the empty string.
3197 scf_tmpl_prop_type(const scf_prop_tmpl_t *t, scf_type_t *out)
3199 char *type;
3201 type = _scf_read_single_astring_from_pg(t->prt_pg,
3202 SCF_PROPERTY_TM_TYPE);
3203 if (type != NULL && type[0] == '\0') {
3204 free(type);
3205 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
3206 return (-1);
3208 if (type == NULL) {
3209 if (ismember(scf_error(), errors_server)) {
3210 return (-1);
3211 } else switch (scf_error()) {
3212 case SCF_ERROR_CONSTRAINT_VIOLATED:
3213 case SCF_ERROR_TYPE_MISMATCH:
3214 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
3215 /*FALLTHROUGH*/
3217 case SCF_ERROR_NOT_FOUND:
3218 return (-1);
3220 case SCF_ERROR_INVALID_ARGUMENT:
3221 case SCF_ERROR_NOT_SET:
3222 default:
3223 assert(0);
3224 abort();
3228 *out = scf_string_to_type(type);
3229 free(type);
3231 if (*out == SCF_TYPE_INVALID) {
3232 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
3233 return (-1);
3236 return (0);
3240 * Returns -1 on failure, sets scf_error() to:
3241 * SCF_ERROR_BACKEND_ACCESS
3242 * SCF_ERROR_CONNECTION_BROKEN
3243 * SCF_ERROR_DELETED
3244 * Property group which represents t was deleted.
3245 * SCF_ERROR_HANDLE_DESTROYED
3246 * SCF_ERROR_INTERNAL
3247 * SCF_ERROR_NO_MEMORY
3248 * SCF_ERROR_NO_RESOURCES
3249 * SCF_ERROR_NOT_BOUND
3250 * SCF_ERROR_PERMISSION_DENIED
3251 * SCF_ERROR_TEMPLATE_INVALID
3252 * required property is not SCF_TYPE_ASTRING has more than one value.
3255 scf_tmpl_prop_required(const scf_prop_tmpl_t *t, uint8_t *out)
3257 if (_read_single_boolean_from_pg(t->prt_pg, SCF_PROPERTY_TM_REQUIRED,
3258 out) == -1) {
3259 if (ismember(scf_error(), errors_server)) {
3260 return (-1);
3261 } else switch (scf_error()) {
3262 case SCF_ERROR_CONSTRAINT_VIOLATED:
3263 case SCF_ERROR_TYPE_MISMATCH:
3264 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
3265 return (-1);
3267 case SCF_ERROR_NOT_FOUND:
3268 *out = 0;
3269 return (0);
3271 case SCF_ERROR_INVALID_ARGUMENT:
3272 case SCF_ERROR_NOT_SET:
3273 default:
3274 assert(0);
3275 abort();
3279 return (0);
3283 * Returns -1 on failure. Sets scf_error():
3284 * SCF_ERROR_BACKEND_ACCESS
3285 * SCF_ERROR_CONNECTION_BROKEN
3286 * SCF_ERROR_DELETED
3287 * SCF_ERROR_HANDLE_DESTROYED
3288 * SCF_ERROR_INTERNAL
3289 * SCF_ERROR_NO_MEMORY
3290 * SCF_ERROR_NO_RESOURCES
3291 * SCF_ERROR_NOT_BOUND
3292 * SCF_ERROR_NOT_FOUND
3293 * Property doesn't exist or exists and has no value.
3294 * SCF_ERROR_INVALID_ARGUMENT
3295 * locale is too long to make a property name
3296 * SCF_ERROR_PERMISSION_DENIED
3297 * SCF_ERROR_TEMPLATE_INVALID
3298 * common_name property is not SCF_TYPE_ASTRING has more than one value.
3300 ssize_t
3301 scf_tmpl_prop_common_name(const scf_prop_tmpl_t *t, const char *locale,
3302 char **out)
3304 assert(out != NULL);
3305 if ((*out = _read_localized_astring_from_pg(t->prt_pg,
3306 SCF_PROPERTY_TM_COMMON_NAME_PREFIX, locale)) == NULL)
3307 return (-1);
3309 return (strlen(*out));
3313 * Returns -1 on failure. Sets scf_error():
3314 * SCF_ERROR_BACKEND_ACCESS
3315 * SCF_ERROR_CONNECTION_BROKEN
3316 * SCF_ERROR_DELETED
3317 * SCF_ERROR_HANDLE_DESTROYED
3318 * SCF_ERROR_INTERNAL
3319 * SCF_ERROR_NO_MEMORY
3320 * SCF_ERROR_NO_RESOURCES
3321 * SCF_ERROR_NOT_BOUND
3322 * SCF_ERROR_NOT_FOUND
3323 * Property doesn't exist or exists and has no value.
3324 * SCF_ERROR_INVALID_ARGUMENT
3325 * locale is too long to make a property name
3326 * SCF_ERROR_PERMISSION_DENIED
3327 * SCF_ERROR_TEMPLATE_INVALID
3328 * description property is not SCF_TYPE_ASTRING has more than one value.
3330 ssize_t
3331 scf_tmpl_prop_description(const scf_prop_tmpl_t *t, const char *locale,
3332 char **out)
3334 assert(out != NULL);
3335 if ((*out = _read_localized_astring_from_pg(t->prt_pg,
3336 SCF_PROPERTY_TM_DESCRIPTION_PREFIX, locale)) == NULL)
3337 return (-1);
3339 return (strlen(*out));
3343 * Returns -1 on failure. Sets scf_error():
3344 * SCF_ERROR_BACKEND_ACCESS
3345 * SCF_ERROR_CONNECTION_BROKEN
3346 * SCF_ERROR_DELETED
3347 * SCF_ERROR_HANDLE_DESTROYED
3348 * SCF_ERROR_INTERNAL
3349 * SCF_ERROR_NO_MEMORY
3350 * SCF_ERROR_NO_RESOURCES
3351 * SCF_ERROR_NOT_BOUND
3352 * SCF_ERROR_NOT_FOUND
3353 * Property doesn't exist or exists and has no value.
3354 * SCF_ERROR_INVALID_ARGUMENT
3355 * locale is too long to make a property name
3356 * SCF_ERROR_PERMISSION_DENIED
3357 * SCF_ERROR_TEMPLATE_INVALID
3358 * units property is not SCF_TYPE_ASTRING has more than one value.
3360 ssize_t
3361 scf_tmpl_prop_units(const scf_prop_tmpl_t *t, const char *locale, char **out)
3363 assert(out != NULL);
3364 if ((*out = _read_localized_astring_from_pg(t->prt_pg,
3365 SCF_PROPERTY_TM_UNITS_PREFIX, locale)) == NULL)
3366 return (-1);
3368 return (strlen(*out));
3372 * Returns -1 on failure. Sets scf_error():
3373 * SCF_ERROR_BACKEND_ACCESS
3374 * SCF_ERROR_CONNECTION_BROKEN
3375 * SCF_ERROR_DELETED
3376 * SCF_ERROR_HANDLE_DESTROYED
3377 * SCF_ERROR_INTERNAL
3378 * SCF_ERROR_NO_MEMORY
3379 * SCF_ERROR_NO_RESOURCES
3380 * SCF_ERROR_NOT_BOUND
3381 * SCF_ERROR_PERMISSION_DENIED
3382 * SCF_ERROR_TEMPLATE_INVALID
3383 * visibility property is not SCF_TYPE_ASTRING has more than one value.
3386 scf_tmpl_prop_visibility(const scf_prop_tmpl_t *t, uint8_t *out)
3388 char *visibility;
3390 visibility = _scf_read_single_astring_from_pg(t->prt_pg,
3391 SCF_PROPERTY_TM_VISIBILITY);
3392 if (visibility == NULL) {
3393 if (ismember(scf_error(), errors_server)) {
3394 return (-1);
3395 } else switch (scf_error()) {
3396 /* prop doesn't exist we take the default value */
3397 case SCF_ERROR_NOT_FOUND:
3398 *out = SCF_TMPL_VISIBILITY_READWRITE;
3399 return (0);
3401 case SCF_ERROR_CONSTRAINT_VIOLATED:
3402 case SCF_ERROR_TYPE_MISMATCH:
3403 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
3404 return (-1);
3406 case SCF_ERROR_INVALID_ARGUMENT:
3407 case SCF_ERROR_NOT_SET:
3408 default:
3409 assert(0);
3410 abort();
3412 } else if (strcmp(visibility, SCF_TM_VISIBILITY_READWRITE) == 0) {
3413 *out = SCF_TMPL_VISIBILITY_READWRITE;
3414 } else if (strcmp(visibility, SCF_TM_VISIBILITY_HIDDEN) == 0) {
3415 *out = SCF_TMPL_VISIBILITY_HIDDEN;
3416 } else if (strcmp(visibility, SCF_TM_VISIBILITY_READONLY) == 0) {
3417 *out = SCF_TMPL_VISIBILITY_READONLY;
3418 } else {
3419 free(visibility);
3420 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
3421 return (-1);
3424 free(visibility);
3425 return (0);
3429 * Return an allocated string containing the value that must be freed
3430 * with free().
3432 * On error set scf_error() _NO_MEMORY, or _NOT_SET (val has not been set
3433 * to a value).
3435 static char *
3436 _scf_value_get_as_string(scf_value_t *val)
3438 ssize_t sz = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH) + 1;
3439 char *buf = malloc(sz);
3441 if (buf == NULL) {
3442 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
3443 } else if (scf_value_get_as_string(val, buf, sz) == -1) {
3444 free(buf);
3445 buf = NULL;
3448 return (buf);
3452 * Returns -1 on failure, sets scf_error() to:
3453 * SCF_ERROR_BACKEND_ACCESS
3454 * SCF_ERROR_CONNECTION_BROKEN
3455 * SCF_ERROR_DELETED
3456 * SCF_ERROR_HANDLE_DESTROYED
3457 * SCF_ERROR_INTERNAL
3458 * SCF_ERROR_NO_MEMORY
3459 * SCF_ERROR_NO_RESOURCES
3460 * SCF_ERROR_NOT_BOUND
3461 * SCF_ERROR_NOT_FOUND
3462 * SCF_ERROR_PERMISSION_DENIED
3463 * SCF_ERROR_TEMPLATE_INVALID
3466 scf_tmpl_prop_cardinality(const scf_prop_tmpl_t *t, uint64_t *min,
3467 uint64_t *max)
3469 scf_value_t *val_min = NULL;
3470 scf_value_t *val_max = NULL;
3471 int ret = 0;
3473 if (_read_single_value_from_pg(t->prt_pg,
3474 SCF_PROPERTY_TM_CARDINALITY_MIN, &val_min) == 0) {
3475 if (scf_value_get_count(val_min, min) < 0)
3476 goto error;
3477 } else {
3478 if (scf_error() == SCF_ERROR_NOT_FOUND)
3479 *min = 0;
3480 else
3481 goto error;
3484 if (_read_single_value_from_pg(t->prt_pg,
3485 SCF_PROPERTY_TM_CARDINALITY_MAX, &val_max) == 0) {
3486 if (scf_value_get_count(val_max, max) < 0)
3487 goto error;
3488 } else {
3489 if (scf_error() == SCF_ERROR_NOT_FOUND)
3490 *max = UINT64_MAX;
3491 else
3492 goto error;
3494 goto cleanup;
3496 error:
3497 if (ismember(scf_error(), errors_server)) {
3498 ret = -1;
3499 } else switch (scf_error()) {
3500 case SCF_ERROR_TYPE_MISMATCH:
3501 case SCF_ERROR_CONSTRAINT_VIOLATED:
3502 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
3503 /*FALLTHROUGH*/
3505 case SCF_ERROR_NOT_FOUND:
3506 case SCF_ERROR_TEMPLATE_INVALID:
3507 ret = -1;
3508 break;
3510 case SCF_ERROR_NOT_SET:
3511 case SCF_ERROR_INVALID_ARGUMENT:
3512 default:
3513 assert(0);
3514 abort();
3517 cleanup:
3518 scf_value_destroy(val_min);
3519 scf_value_destroy(val_max);
3521 return (ret);
3525 * Returns -1 on failure. Sets scf_error():
3526 * SCF_ERROR_BACKEND_ACCESS
3527 * SCF_ERROR_CONNECTION_BROKEN
3528 * SCF_ERROR_DELETED
3529 * SCF_ERROR_HANDLE_DESTROYED
3530 * SCF_ERROR_INTERNAL
3531 * SCF_ERROR_NO_MEMORY
3532 * SCF_ERROR_NO_RESOURCES
3533 * SCF_ERROR_NOT_BOUND
3534 * SCF_ERROR_NOT_FOUND
3535 * Property doesn't exist or exists and has no value.
3536 * SCF_ERROR_PERMISSION_DENIED
3537 * SCF_ERROR_TEMPLATE_INVALID
3540 scf_tmpl_prop_internal_seps(const scf_prop_tmpl_t *t, scf_values_t *vals)
3542 if (_read_astrings_values(t->prt_pg,
3543 SCF_PROPERTY_INTERNAL_SEPARATORS, vals) == NULL) {
3544 if (ismember(scf_error(), errors_server)) {
3545 return (-1);
3546 } else switch (scf_error()) {
3547 case SCF_ERROR_CONSTRAINT_VIOLATED:
3548 case SCF_ERROR_TYPE_MISMATCH:
3549 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
3550 /*FALLTHROUGH*/
3552 case SCF_ERROR_NOT_FOUND:
3553 return (-1);
3555 case SCF_ERROR_INVALID_ARGUMENT:
3556 case SCF_ERROR_NOT_SET:
3557 default:
3558 assert(0);
3559 abort();
3561 } else if (vals->value_count == 0) {
3562 /* property has no value */
3563 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
3564 scf_values_destroy(vals);
3565 return (-1);
3568 return (0);
3572 * Returns -1 on failure. Sets scf_error():
3573 * SCF_ERROR_BACKEND_ACCESS
3574 * SCF_ERROR_CONNECTION_BROKEN
3575 * SCF_ERROR_DELETED
3576 * SCF_ERROR_HANDLE_DESTROYED
3577 * SCF_ERROR_INTERNAL
3578 * SCF_ERROR_NO_MEMORY
3579 * SCF_ERROR_NO_RESOURCES
3580 * SCF_ERROR_NOT_BOUND
3581 * SCF_ERROR_NOT_FOUND
3582 * Property doesn't exist or exists and has no value.
3583 * SCF_ERROR_PERMISSION_DENIED
3584 * SCF_ERROR_TEMPLATE_INVALID
3587 scf_tmpl_value_name_constraints(const scf_prop_tmpl_t *t,
3588 scf_values_t *vals)
3590 char **ret;
3592 ret = _read_astrings_values(t->prt_pg,
3593 SCF_PROPERTY_TM_CONSTRAINT_NAME, vals);
3595 if (ret == NULL) {
3596 if (ismember(scf_error(), errors_server)) {
3597 return (-1);
3598 } else switch (scf_error()) {
3599 case SCF_ERROR_CONSTRAINT_VIOLATED:
3600 case SCF_ERROR_TYPE_MISMATCH:
3601 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
3602 /*FALLTHROUGH*/
3604 case SCF_ERROR_NOT_FOUND:
3605 return (-1);
3607 case SCF_ERROR_INVALID_ARGUMENT:
3608 case SCF_ERROR_NOT_SET:
3609 default:
3610 assert(0);
3611 abort();
3613 } else if (vals->value_count == 0) {
3614 /* property has no value */
3615 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
3616 scf_values_destroy(vals);
3617 return (-1);
3620 return (0);
3624 * Returns NULL on failure. Sets scf_error():
3625 * Caller is responsible for freeing returned pointer after use.
3626 * SCF_ERROR_CONSTRAINT_VIOLATED
3627 * More tokens than the array size supplied.
3628 * SCF_ERROR_NO_MEMORY
3630 static void *
3631 _separate_by_separator(char *string, const char *sep, char **array, int size)
3633 char *str, *token;
3634 char *lasts;
3635 int n = 0;
3637 assert(array != NULL);
3638 assert(string != NULL);
3639 assert(sep != NULL);
3640 assert(size > 0);
3642 str = strdup(string);
3643 if (str == NULL) {
3644 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
3645 return (NULL);
3648 if ((array[n] = strtok_r(str, sep, &lasts)) == NULL) {
3649 assert(0);
3650 abort();
3653 n++;
3654 while ((token = strtok_r(NULL, sep, &lasts)) != NULL) {
3655 if (n >= size) {
3656 goto error;
3658 array[n] = token;
3659 n++;
3661 if (n < size) {
3662 goto error;
3665 return (str);
3666 error:
3667 free(str);
3668 (void) scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
3669 return (NULL);
3673 * check if name is among values of CHOICES_INCLUDE_VALUES
3674 * return 0 if name is present, 1 name is not present, -1 on failure
3675 * SCF_ERROR_BACKEND_ACCESS
3676 * SCF_ERROR_CONNECTION_BROKEN
3677 * SCF_ERROR_DELETED
3678 * SCF_ERROR_HANDLE_DESTROYED
3679 * SCF_ERROR_INTERNAL
3680 * SCF_ERROR_NO_MEMORY
3681 * SCF_ERROR_NO_RESOURCES
3682 * SCF_ERROR_NOT_BOUND
3683 * SCF_ERROR_PERMISSION_DENIED
3684 * SCF_ERROR_TEMPLATE_INVALID
3686 static int
3687 _check_choices_include_values(scf_propertygroup_t *pg, const char *name)
3689 int n = 0, r = 1;
3690 char **ret;
3691 scf_values_t vals;
3693 if ((ret = _read_astrings_values(pg,
3694 SCF_PROPERTY_TM_CHOICES_INCLUDE_VALUES, &vals)) == NULL) {
3695 if (ismember(scf_error(), errors_server)) {
3696 return (-1);
3697 } else switch (scf_error()) {
3698 case SCF_ERROR_NOT_FOUND:
3699 return (1);
3701 case SCF_ERROR_TYPE_MISMATCH:
3702 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
3703 return (-1);
3705 case SCF_ERROR_INVALID_ARGUMENT:
3706 case SCF_ERROR_NOT_SET:
3707 default:
3708 assert(0);
3709 abort();
3713 for (n = 0; n < vals.value_count; ++n) {
3714 if (strcmp(name, ret[n]) == 0) {
3715 r = 0;
3716 break;
3719 scf_values_destroy(&vals);
3720 return (r);
3723 void
3724 scf_count_ranges_destroy(scf_count_ranges_t *ranges)
3726 if (ranges == NULL)
3727 return;
3729 ranges->scr_num_ranges = 0;
3730 free(ranges->scr_min);
3731 free(ranges->scr_max);
3732 ranges->scr_min = NULL;
3733 ranges->scr_max = NULL;
3736 void
3737 scf_int_ranges_destroy(scf_int_ranges_t *ranges)
3739 if (ranges == NULL)
3740 return;
3742 ranges->sir_num_ranges = 0;
3743 free(ranges->sir_min);
3744 free(ranges->sir_max);
3745 ranges->sir_min = NULL;
3746 ranges->sir_max = NULL;
3750 * Returns -1 on failure. Sets scf_error():
3751 * SCF_ERROR_BACKEND_ACCESS
3752 * SCF_ERROR_CONNECTION_BROKEN
3753 * SCF_ERROR_CONSTRAINT_VIOLATED
3754 * SCF_ERROR_DELETED
3755 * SCF_ERROR_HANDLE_DESTROYED
3756 * SCF_ERROR_INTERNAL
3757 * SCF_ERROR_NO_MEMORY
3758 * SCF_ERROR_NO_RESOURCES
3759 * SCF_ERROR_NOT_BOUND
3760 * SCF_ERROR_NOT_FOUND
3761 * Property doesn't exist or exists and has no value.
3762 * SCF_ERROR_PERMISSION_DENIED
3763 * SCF_ERROR_TEMPLATE_INVALID
3765 static int
3766 _scf_tmpl_get_count_ranges(const scf_prop_tmpl_t *t, const char *prop,
3767 scf_count_ranges_t *ranges)
3769 scf_values_t vals;
3770 int i = 0;
3771 char **ret;
3772 char *one_range[2];
3773 char *endptr;
3774 char *str = NULL;
3775 uint64_t *min = NULL;
3776 uint64_t *max = NULL;
3778 assert(ranges != NULL);
3779 if ((ret = _read_astrings_values(t->prt_pg, prop, &vals)) == NULL)
3780 goto error;
3781 if (vals.value_count == 0) {
3782 /* range values are empty */
3783 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
3784 goto cleanup;
3787 min = malloc(vals.value_count * sizeof (uint64_t));
3788 max = malloc(vals.value_count * sizeof (uint64_t));
3789 if (min == NULL || max == NULL) {
3790 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
3791 goto cleanup;
3793 for (i = 0; i < vals.value_count; ++i) {
3794 /* min and max should be separated by a "," */
3795 if ((str = _separate_by_separator(ret[i], ",", one_range,
3796 2)) == NULL)
3797 goto cleanup;
3798 errno = 0;
3799 min[i] = strtoull(one_range[0], &endptr, 10);
3800 if (errno != 0 || endptr == one_range[0] || *endptr) {
3801 (void) scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
3802 goto cleanup;
3804 errno = 0;
3805 max[i] = strtoull(one_range[1], &endptr, 10);
3806 if (errno != 0 || endptr == one_range[1] || *endptr) {
3807 (void) scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
3808 goto cleanup;
3810 if (min[i] > max[i]) {
3811 (void) scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
3812 goto cleanup;
3814 free(str);
3815 str = NULL;
3817 ranges->scr_num_ranges = vals.value_count;
3818 ranges->scr_min = min;
3819 ranges->scr_max = max;
3820 scf_values_destroy(&vals);
3821 return (0);
3822 cleanup:
3823 free(str);
3824 free(min);
3825 free(max);
3826 scf_values_destroy(&vals);
3827 error:
3828 if (ismember(scf_error(), errors_server)) {
3829 return (-1);
3830 } else switch (scf_error()) {
3831 case SCF_ERROR_TYPE_MISMATCH:
3832 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
3833 /*FALLTHROUGH*/
3835 case SCF_ERROR_CONSTRAINT_VIOLATED:
3836 case SCF_ERROR_NOT_FOUND:
3837 return (-1);
3839 case SCF_ERROR_INVALID_ARGUMENT:
3840 case SCF_ERROR_NOT_SET:
3841 default:
3842 assert(0);
3843 abort();
3845 /*NOTREACHED*/
3849 * Returns -1 on failure. Sets scf_error():
3850 * SCF_ERROR_BACKEND_ACCESS
3851 * SCF_ERROR_CONNECTION_BROKEN
3852 * SCF_ERROR_CONSTRAINT_VIOLATED
3853 * SCF_ERROR_DELETED
3854 * SCF_ERROR_HANDLE_DESTROYED
3855 * SCF_ERROR_INTERNAL
3856 * SCF_ERROR_NO_MEMORY
3857 * SCF_ERROR_NO_RESOURCES
3858 * SCF_ERROR_NOT_BOUND
3859 * SCF_ERROR_NOT_FOUND
3860 * Property doesn't exist or exists and has no value.
3861 * SCF_ERROR_PERMISSION_DENIED
3862 * SCF_ERROR_TEMPLATE_INVALID
3864 static int
3865 _scf_tmpl_get_int_ranges(const scf_prop_tmpl_t *t, const char *prop,
3866 scf_int_ranges_t *ranges)
3868 scf_values_t vals;
3869 int n = 0;
3870 char **ret;
3871 char *one_range[2];
3872 char *endptr;
3873 char *str = NULL;
3874 int64_t *min = NULL;
3875 int64_t *max = NULL;
3877 assert(ranges != NULL);
3878 if ((ret = _read_astrings_values(t->prt_pg, prop, &vals)) == NULL)
3879 goto error;
3880 if (vals.value_count == 0) {
3881 /* range values are empty */
3882 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
3883 goto cleanup;
3886 min = malloc(vals.value_count * sizeof (int64_t));
3887 max = malloc(vals.value_count * sizeof (int64_t));
3888 if (min == NULL || max == NULL) {
3889 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
3890 goto cleanup;
3892 while (n < vals.value_count) {
3893 /* min and max should be separated by a "," */
3894 if ((str = _separate_by_separator(ret[n], ",", one_range, 2))
3895 == NULL)
3896 goto cleanup;
3897 errno = 0;
3898 min[n] = strtoll(one_range[0], &endptr, 10);
3899 if (errno != 0 || endptr == one_range[0] || *endptr) {
3900 (void) scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
3901 goto cleanup;
3903 errno = 0;
3904 max[n] = strtoll(one_range[1], &endptr, 10);
3905 if (errno != 0 || endptr == one_range[1] || *endptr) {
3906 (void) scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
3907 goto cleanup;
3909 if (min[n] > max[n]) {
3910 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
3911 goto cleanup;
3913 ++n;
3914 free(str);
3915 str = NULL;
3917 ranges->sir_num_ranges = vals.value_count;
3918 ranges->sir_min = min;
3919 ranges->sir_max = max;
3920 scf_values_destroy(&vals);
3921 return (0);
3922 cleanup:
3923 free(str);
3924 free(min);
3925 free(max);
3926 scf_values_destroy(&vals);
3927 error:
3928 if (ismember(scf_error(), errors_server)) {
3929 return (-1);
3930 } else switch (scf_error()) {
3931 case SCF_ERROR_TYPE_MISMATCH:
3932 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
3933 /*FALLTHROUGH*/
3935 case SCF_ERROR_CONSTRAINT_VIOLATED:
3936 case SCF_ERROR_NOT_FOUND:
3937 case SCF_ERROR_TEMPLATE_INVALID:
3938 return (-1);
3940 case SCF_ERROR_INVALID_ARGUMENT:
3941 case SCF_ERROR_NOT_SET:
3942 default:
3943 assert(0);
3944 abort();
3946 /*NOTREACHED*/
3950 * Returns -1 on failure. Sets scf_error():
3951 * SCF_ERROR_BACKEND_ACCESS
3952 * SCF_ERROR_CONNECTION_BROKEN
3953 * SCF_ERROR_CONSTRAINT_VIOLATED
3954 * SCF_ERROR_DELETED
3955 * SCF_ERROR_HANDLE_DESTROYED
3956 * SCF_ERROR_INTERNAL
3957 * SCF_ERROR_NO_MEMORY
3958 * SCF_ERROR_NO_RESOURCES
3959 * SCF_ERROR_NOT_BOUND
3960 * SCF_ERROR_NOT_FOUND
3961 * Property doesn't exist or exists and has no value.
3962 * SCF_ERROR_PERMISSION_DENIED
3963 * SCF_ERROR_TEMPLATE_INVALID
3966 scf_tmpl_value_count_range_constraints(const scf_prop_tmpl_t *t,
3967 scf_count_ranges_t *ranges)
3969 return (_scf_tmpl_get_count_ranges(t, SCF_PROPERTY_TM_CONSTRAINT_RANGE,
3970 ranges));
3974 scf_tmpl_value_int_range_constraints(const scf_prop_tmpl_t *t,
3975 scf_int_ranges_t *ranges)
3977 return (_scf_tmpl_get_int_ranges(t, SCF_PROPERTY_TM_CONSTRAINT_RANGE,
3978 ranges));
3982 scf_tmpl_value_count_range_choices(const scf_prop_tmpl_t *t,
3983 scf_count_ranges_t *ranges)
3985 return (_scf_tmpl_get_count_ranges(t, SCF_PROPERTY_TM_CHOICES_RANGE,
3986 ranges));
3990 scf_tmpl_value_int_range_choices(const scf_prop_tmpl_t *t,
3991 scf_int_ranges_t *ranges)
3993 return (_scf_tmpl_get_int_ranges(t, SCF_PROPERTY_TM_CHOICES_RANGE,
3994 ranges));
3998 * Returns -1 on failure. Sets scf_error():
3999 * SCF_ERROR_BACKEND_ACCESS
4000 * SCF_ERROR_CONNECTION_BROKEN
4001 * SCF_ERROR_DELETED
4002 * SCF_ERROR_HANDLE_DESTROYED
4003 * SCF_ERROR_INTERNAL
4004 * SCF_ERROR_NO_MEMORY
4005 * SCF_ERROR_NO_RESOURCES
4006 * SCF_ERROR_NOT_BOUND
4007 * SCF_ERROR_NOT_FOUND
4008 * Property doesn't exist or exists and has no value.
4009 * SCF_ERROR_PERMISSION_DENIED
4010 * SCF_ERROR_TEMPLATE_INVALID
4013 scf_tmpl_value_name_choices(const scf_prop_tmpl_t *t, scf_values_t *vals)
4015 int c_flag = 0; /* have not read any value yet */
4016 int r;
4017 char **ret;
4019 /* First, look for explicitly declared choices. */
4020 if ((ret = _read_astrings_values(t->prt_pg,
4021 SCF_PROPERTY_TM_CHOICES_NAME, vals)) != NULL) {
4022 c_flag = 1;
4023 } else if (scf_error() != SCF_ERROR_NOT_FOUND) {
4024 goto error;
4027 /* Next, check for choices included by 'values'. */
4028 if ((r = _check_choices_include_values(t->prt_pg, "values")) == 0) {
4029 /* read values_name */
4030 if (c_flag == 1)
4031 /* append values */
4032 ret = _append_astrings_values(t->prt_pg,
4033 SCF_PROPERTY_TM_VALUES_NAME, vals);
4034 else
4035 /* read values */
4036 ret = _read_astrings_values(t->prt_pg,
4037 SCF_PROPERTY_TM_VALUES_NAME, vals);
4038 if (ret != NULL) {
4039 c_flag = 1;
4040 } else if (scf_error() != SCF_ERROR_NOT_FOUND) {
4041 goto error;
4043 } else if (r == -1) {
4044 goto error;
4047 /* Finally check for choices included by 'constraints'. */
4048 if ((r = _check_choices_include_values(t->prt_pg, "constraints")) ==
4049 0) {
4050 /* read constraint_name */
4051 if (c_flag == 1)
4052 /* append values */
4053 ret = _append_astrings_values(t->prt_pg,
4054 SCF_PROPERTY_TM_CONSTRAINT_NAME, vals);
4055 else
4056 /* read values */
4057 ret = _read_astrings_values(t->prt_pg,
4058 SCF_PROPERTY_TM_CONSTRAINT_NAME, vals);
4059 if (ret != NULL) {
4060 c_flag = 1;
4061 } else if (scf_error() != SCF_ERROR_NOT_FOUND) {
4062 goto error;
4064 } else if (r == -1) {
4065 goto error;
4068 if (c_flag == 0 || vals->value_count == 0) {
4069 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
4070 return (-1);
4073 return (0);
4075 error:
4076 if (ismember(scf_error(), errors_server)) {
4077 return (-1);
4078 } else switch (scf_error()) {
4079 case SCF_ERROR_TYPE_MISMATCH:
4080 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
4081 return (-1);
4083 case SCF_ERROR_NOT_SET:
4084 case SCF_ERROR_INVALID_ARGUMENT:
4085 default:
4086 assert(0);
4087 abort();
4089 /*NOTREACHED*/
4092 void
4093 scf_values_destroy(scf_values_t *vals)
4095 int i;
4096 char **items = NULL;
4097 char **str = NULL;
4099 if (vals == NULL)
4100 return;
4102 str = vals->values_as_strings;
4104 /* free values */
4105 switch (vals->value_type) {
4106 case SCF_TYPE_BOOLEAN:
4107 free(vals->values.v_boolean);
4108 break;
4109 case SCF_TYPE_COUNT:
4110 free(vals->values.v_count);
4111 break;
4112 case SCF_TYPE_INTEGER:
4113 free(vals->values.v_integer);
4114 break;
4115 case SCF_TYPE_ASTRING:
4116 items = vals->values.v_astring;
4117 str = NULL;
4118 break;
4119 case SCF_TYPE_USTRING:
4120 items = vals->values.v_ustring;
4121 str = NULL;
4122 break;
4123 case SCF_TYPE_OPAQUE:
4124 items = vals->values.v_opaque;
4125 str = NULL;
4126 break;
4127 case SCF_TYPE_TIME:
4128 free(vals->values.v_time);
4129 break;
4130 default:
4131 assert(0);
4132 abort();
4134 for (i = 0; i < vals->value_count; ++i) {
4135 if (items != NULL)
4136 free(items[i]);
4137 if (str != NULL)
4138 free(str[i]);
4140 vals->value_count = 0;
4141 free(items);
4142 free(str);
4146 * char *_make_value_name()
4148 * Construct the prefix for a value common name or value description property.
4149 * It takes the form:
4150 * value_<BASE32 name>_<common_name|description>_
4151 * This is then combined with a localized suffix by the caller to look
4152 * up the property in the repository:
4153 * value_<BASE32 name>_<common_name|description>_<lang>
4155 * Returns NULL on failure. Sets scf_error():
4156 * SCF_ERROR_INVALID_ARGUMENT
4157 * Name isn't short enough make a value name with.
4158 * SCF_ERROR_NO_MEMORY
4160 static char *
4161 _make_value_name(char *desc_name, const char *value)
4163 char *name = NULL;
4164 char *encoded = NULL;
4165 ssize_t sz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
4167 name = malloc(sz);
4168 encoded = malloc(sz);
4169 if (name == NULL || encoded == NULL) {
4170 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
4171 free(name);
4172 free(encoded);
4173 return (NULL);
4176 if (scf_encode32(value, strlen(value), encoded, sz, NULL,
4177 SCF_ENCODE32_PAD) != 0) {
4178 /* Shouldn't happen. */
4179 assert(0);
4182 (void) strlcpy(name, SCF_PROPERTY_TM_VALUE_PREFIX, sz);
4184 if (strlcat(name, encoded, sz) >= sz) {
4185 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
4186 free(name);
4187 free(encoded);
4188 return (NULL);
4191 if (strlcat(name, "_", sz) >= sz) {
4192 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
4193 free(name);
4194 free(encoded);
4195 return (NULL);
4198 if (strlcat(name, desc_name, sz) >= sz) {
4199 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
4200 free(name);
4201 free(encoded);
4202 return (NULL);
4205 if (strlcat(name, "_", sz) >= sz) {
4206 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
4207 free(name);
4208 free(encoded);
4209 return (NULL);
4212 free(encoded);
4213 return (name);
4217 * ssize_t scf_tmpl_value_common_name()
4219 * Populates "out" with an allocated string containing the value's
4220 * common name. Returns the size of the string on successful return.
4221 * out must be freed with free() on successful return.
4223 * Returns -1 on failure, sets scf_error() to:
4224 * SCF_ERROR_BACKEND_ACCESS
4225 * SCF_ERROR_CONNECTION_BROKEN
4226 * SCF_ERROR_DELETED
4227 * Property group was deleted.
4228 * SCF_ERROR_HANDLE_DESTROYED
4229 * SCF_ERROR_INTERNAL
4230 * SCF_ERROR_INVALID_ARGUMENT
4231 * name not a valid property name
4232 * name and locale are too long to make a property name
4233 * SCF_ERROR_NO_MEMORY
4234 * SCF_ERROR_NO_RESOURCES
4235 * SCF_ERROR_NOT_BOUND
4236 * SCF_ERROR_NOT_FOUND
4237 * Property doesn't exist or exists and has no value.
4238 * SCF_ERROR_PERMISSION_DENIED
4239 * SCF_ERROR_TEMPLATE_INVALID
4240 * property is not SCF_TYPE_ASTRING has more than one value.
4242 ssize_t
4243 scf_tmpl_value_common_name(const scf_prop_tmpl_t *t, const char *locale,
4244 const char *value, char **out)
4246 char *value_name = NULL;
4248 value_name = _make_value_name("common_name", value);
4249 if (value_name == NULL)
4250 return (-1);
4252 *out = _read_localized_astring_from_pg(t->prt_pg, value_name, locale);
4254 free(value_name);
4256 if (*out == NULL)
4257 return (-1);
4259 return (strlen(*out));
4263 * ssize_t scf_tmpl_value_description()
4265 * Populates "out" with an allocated string containing the value's
4266 * description. Returns the size of the string on successful return.
4267 * out must be freed with free() on successful return.
4269 * Returns -1 on failure, sets scf_error() to:
4270 * SCF_ERROR_BACKEND_ACCESS
4271 * SCF_ERROR_CONNECTION_BROKEN
4272 * SCF_ERROR_DELETED
4273 * Property group was deleted.
4274 * SCF_ERROR_HANDLE_DESTROYED
4275 * SCF_ERROR_INTERNAL
4276 * SCF_ERROR_INVALID_ARGUMENT
4277 * name not a valid property name
4278 * name and locale are too long to make a property name
4279 * SCF_ERROR_NO_MEMORY
4280 * SCF_ERROR_NO_RESOURCES
4281 * SCF_ERROR_NOT_BOUND
4282 * SCF_ERROR_NOT_FOUND
4283 * Property doesn't exist or exists and has no value.
4284 * SCF_ERROR_PERMISSION_DENIED
4285 * SCF_ERROR_TEMPLATE_INVALID
4286 * property is not SCF_TYPE_ASTRING has more than one value.
4288 ssize_t
4289 scf_tmpl_value_description(const scf_prop_tmpl_t *t, const char *locale,
4290 const char *value, char **out)
4292 char *value_name = NULL;
4294 value_name = _make_value_name("description", value);
4295 if (value_name == NULL)
4296 return (-1);
4299 *out = _read_localized_astring_from_pg(t->prt_pg, value_name, locale);
4301 free(value_name);
4303 if (*out == NULL)
4304 return (-1);
4306 return (strlen(*out));
4310 * Templates error messages format, in human readable form.
4311 * Each line is one error item:
4313 * prefix error message
4314 * FMRI="err->te_errs->tes_fmri"
4315 * Property group="err->te_pg_name"
4316 * Property name="err->te_prop_name"
4317 * expected value 1="err->te_ev1"
4318 * expected value 2="err->te_ev2"
4319 * actual value="err->te_actual"
4320 * Tempalte source="err->te_tmpl_fmri"
4321 * pg_pattern name="err->tmpl_pg_name"
4322 * pg_pattern type="err->tmpl_pg_type"
4323 * prop_pattern name="err->tmpl_prop_name"
4324 * prop_pattern type="err->tmpl_prop_type"
4326 * To add a new error type, include scf_tmpl_error_type_t in libscf.h
4327 * add one entry in em_desc[], and update the functions pointed by the
4328 * _tmpl_error_access array with the new error code. Also, update the
4329 * scf_tmpl_error_* functions to provide access to desired
4330 * scf_tmpl_error_t fields.
4332 * To add a new error item, add a new field to scf_tmpl_error_t, a new field
4333 * in _scf_tmpl_error_desc or a new non-error-dependent string, add a new entry
4334 * in _tmpl_error_access array and create the appropriate get_val, get_desc
4335 * functions.
4337 * Changes to both the validation logic and the error types and items must
4338 * be coordinated with the code in svccfg to ensure both libscf and svccfg's
4339 * manifest validation validate the same things.
4343 * Container for all template errors on a validated object.
4345 struct scf_tmpl_errors {
4346 int tes_index;
4347 int tes_num_errs;
4348 scf_tmpl_error_t **tes_errs;
4349 int tes_errs_size;
4350 const char *tes_fmri;
4351 const char *tes_prefix;
4352 int tes_flag; /* if set, scf_tmpl_error_destroy */
4353 /* will free strings in tes_errs */
4357 * Templates error-dependent labels
4359 struct _scf_tmpl_error_desc {
4360 const char *em_msg;
4361 const char *em_ev1;
4362 const char *em_ev2;
4363 const char *em_actual;
4367 * This array MUST be kept in synch with the template error definition of
4368 * scf_tmpl_error_type_t in libscf.h
4370 static struct _scf_tmpl_error_desc em_desc[] = {
4371 /* SCF_TERR_MISSING_PG */
4372 { "Required property group missing", "Name of missing property group",
4373 "Type of missing property group", NULL },
4374 /* SCF_TERR_WRONG_PG_TYPE */
4375 { "Property group has bad type", "Specified type", NULL,
4376 "Actual type" },
4377 /* SCF_TERR_MISSING_PROP */
4378 { "Required property missing", "Name of missing property", NULL, NULL },
4379 /* SCF_TERR_WRONG_PROP_TYPE */
4380 { "Property has bad type", "Specified property type", NULL,
4381 "Actual property type" },
4382 /* SCF_TERR_CARDINALITY_VIOLATION */
4383 { "Number of property values violates cardinality restriction",
4384 "Cardinality minimum", "Cardinality maximum",
4385 "Actual number of values" },
4386 /* SCF_TERR_VALUE_CONSTRAINT_VIOLATED */
4387 { "Property has illegal value", NULL, NULL, "Illegal value" },
4388 /* SCF_TERR_RANGE_VIOLATION */
4389 { "Property value is out of range", NULL, NULL, "Actual value" },
4390 /* SCF_TERR_PG_REDEFINE */
4391 { "Instance redefines pg_pattern", "Instance pg_pattern name",
4392 "Instance pg_pattern type", NULL },
4393 /* SCF_TERR_PROP_TYPE_MISMATCH */
4394 { "Property type and value type mismatch", NULL, NULL, "Value type" },
4395 /* SCF_TERR_VALUE_OUT_OF_RANGE */
4396 { "Value is out of range", NULL, NULL, "Value" },
4397 /* SCF_TERR_INVALID_VALUE */
4398 { "Value is not valid", NULL, NULL, "Value" },
4399 /* SCF_TERR_PG_PATTERN_CONFLICT */
4400 { "Conflicting pg_pattern specifications", "Template source",
4401 "pg_pattern name", "pg_pattern type" },
4402 /* SCF_TERR_PROP_PATTERN_CONFLICT */
4403 { "Conflicting prop_pattern specifications", "Template source",
4404 "prop_pattern name", "prop_pattern type" },
4405 /* SCF_TERR_GENERAL_REDEFINE */
4406 { "Service or instance pg_pattern redefines a global or restarter "
4407 "pg_pattern", "Template source", "pg_pattern name",
4408 "pg_pattern type" },
4409 /* SCF_TERR_INCLUDE_VALUES */
4410 { "Missing constraints or values for include_values element",
4411 "include_values type", NULL, NULL },
4412 /* SCF_TERR_PG_PATTERN_INCOMPLETE */
4413 { "Required pg_pattern is missing a name or type attribute",
4414 NULL, NULL, NULL },
4415 /* SCF_TERR_PROP_PATTERN_INCOMPLETE */
4416 { "Required prop_pattern is missing a type attribute",
4417 NULL, NULL, NULL }
4421 * Templates non error-dependent labels
4423 static const char *em_fmri = "FMRI";
4424 static const char *em_pg_name = "Property group";
4425 static const char *em_prop_name = "Property name";
4426 static const char *em_tmpl_fmri = "Template source";
4427 static const char *em_tmpl_pg_name = "pg_pattern name";
4428 static const char *em_tmpl_pg_type = "pg_pattern type";
4429 static const char *em_tmpl_prop_name = "prop_pattern name";
4430 static const char *em_tmpl_prop_type = "prop_pattern type";
4432 static const char *
4433 _get_fmri_desc(scf_tmpl_error_t *err)
4435 switch (err->te_type) {
4436 case SCF_TERR_MISSING_PG:
4437 case SCF_TERR_WRONG_PG_TYPE:
4438 case SCF_TERR_MISSING_PROP:
4439 case SCF_TERR_WRONG_PROP_TYPE:
4440 case SCF_TERR_CARDINALITY_VIOLATION:
4441 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
4442 case SCF_TERR_RANGE_VIOLATION:
4443 case SCF_TERR_PG_REDEFINE:
4444 case SCF_TERR_PG_PATTERN_INCOMPLETE:
4445 case SCF_TERR_PROP_PATTERN_INCOMPLETE:
4446 case SCF_TERR_INCLUDE_VALUES:
4447 return (dgettext(TEXT_DOMAIN, em_fmri));
4448 case SCF_TERR_PROP_TYPE_MISMATCH:
4449 case SCF_TERR_VALUE_OUT_OF_RANGE:
4450 case SCF_TERR_INVALID_VALUE:
4451 case SCF_TERR_PG_PATTERN_CONFLICT:
4452 case SCF_TERR_PROP_PATTERN_CONFLICT:
4453 case SCF_TERR_GENERAL_REDEFINE:
4454 default:
4455 return (NULL);
4459 static const char *
4460 _get_pg_name_desc(scf_tmpl_error_t *err)
4462 switch (err->te_type) {
4463 case SCF_TERR_WRONG_PG_TYPE:
4464 case SCF_TERR_MISSING_PROP:
4465 case SCF_TERR_WRONG_PROP_TYPE:
4466 case SCF_TERR_CARDINALITY_VIOLATION:
4467 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
4468 case SCF_TERR_RANGE_VIOLATION:
4469 return (dgettext(TEXT_DOMAIN, em_pg_name));
4470 case SCF_TERR_MISSING_PG:
4471 case SCF_TERR_PG_REDEFINE:
4472 case SCF_TERR_PROP_TYPE_MISMATCH:
4473 case SCF_TERR_VALUE_OUT_OF_RANGE:
4474 case SCF_TERR_INVALID_VALUE:
4475 case SCF_TERR_PG_PATTERN_CONFLICT:
4476 case SCF_TERR_PROP_PATTERN_CONFLICT:
4477 case SCF_TERR_GENERAL_REDEFINE:
4478 case SCF_TERR_INCLUDE_VALUES:
4479 case SCF_TERR_PG_PATTERN_INCOMPLETE:
4480 case SCF_TERR_PROP_PATTERN_INCOMPLETE:
4481 default:
4482 return (NULL);
4486 static const char *
4487 _get_prop_name_desc(scf_tmpl_error_t *err)
4489 switch (err->te_type) {
4490 case SCF_TERR_WRONG_PROP_TYPE:
4491 case SCF_TERR_CARDINALITY_VIOLATION:
4492 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
4493 case SCF_TERR_RANGE_VIOLATION:
4494 return (dgettext(TEXT_DOMAIN, em_prop_name));
4495 case SCF_TERR_MISSING_PG:
4496 case SCF_TERR_WRONG_PG_TYPE:
4497 case SCF_TERR_MISSING_PROP:
4498 case SCF_TERR_PG_REDEFINE:
4499 case SCF_TERR_PROP_TYPE_MISMATCH:
4500 case SCF_TERR_VALUE_OUT_OF_RANGE:
4501 case SCF_TERR_INVALID_VALUE:
4502 case SCF_TERR_PG_PATTERN_CONFLICT:
4503 case SCF_TERR_PROP_PATTERN_CONFLICT:
4504 case SCF_TERR_GENERAL_REDEFINE:
4505 case SCF_TERR_INCLUDE_VALUES:
4506 case SCF_TERR_PG_PATTERN_INCOMPLETE:
4507 case SCF_TERR_PROP_PATTERN_INCOMPLETE:
4508 default:
4509 return (NULL);
4513 static const char *
4514 _get_ev1_desc(scf_tmpl_error_t *err)
4516 switch (err->te_type) {
4517 case SCF_TERR_MISSING_PG:
4518 case SCF_TERR_WRONG_PG_TYPE:
4519 case SCF_TERR_MISSING_PROP:
4520 case SCF_TERR_WRONG_PROP_TYPE:
4521 case SCF_TERR_CARDINALITY_VIOLATION:
4522 case SCF_TERR_RANGE_VIOLATION:
4523 case SCF_TERR_PG_REDEFINE:
4524 case SCF_TERR_PG_PATTERN_CONFLICT:
4525 case SCF_TERR_PROP_PATTERN_CONFLICT:
4526 case SCF_TERR_GENERAL_REDEFINE:
4527 case SCF_TERR_INCLUDE_VALUES:
4528 return (dgettext(TEXT_DOMAIN, em_desc[err->te_type].em_ev1));
4529 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
4530 case SCF_TERR_PROP_TYPE_MISMATCH:
4531 case SCF_TERR_VALUE_OUT_OF_RANGE:
4532 case SCF_TERR_INVALID_VALUE:
4533 case SCF_TERR_PG_PATTERN_INCOMPLETE:
4534 case SCF_TERR_PROP_PATTERN_INCOMPLETE:
4535 default:
4536 return (NULL);
4540 static const char *
4541 _get_ev2_desc(scf_tmpl_error_t *err)
4543 switch (err->te_type) {
4544 case SCF_TERR_MISSING_PG:
4545 case SCF_TERR_CARDINALITY_VIOLATION:
4546 case SCF_TERR_RANGE_VIOLATION:
4547 case SCF_TERR_PG_REDEFINE:
4548 case SCF_TERR_PG_PATTERN_CONFLICT:
4549 case SCF_TERR_PROP_PATTERN_CONFLICT:
4550 case SCF_TERR_GENERAL_REDEFINE:
4551 return (dgettext(TEXT_DOMAIN, em_desc[err->te_type].em_ev2));
4552 case SCF_TERR_WRONG_PG_TYPE:
4553 case SCF_TERR_MISSING_PROP:
4554 case SCF_TERR_WRONG_PROP_TYPE:
4555 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
4556 case SCF_TERR_PROP_TYPE_MISMATCH:
4557 case SCF_TERR_VALUE_OUT_OF_RANGE:
4558 case SCF_TERR_INVALID_VALUE:
4559 case SCF_TERR_INCLUDE_VALUES:
4560 case SCF_TERR_PG_PATTERN_INCOMPLETE:
4561 case SCF_TERR_PROP_PATTERN_INCOMPLETE:
4562 default:
4563 return (NULL);
4567 static const char *
4568 _get_actual_desc(scf_tmpl_error_t *err)
4570 switch (err->te_type) {
4571 case SCF_TERR_MISSING_PG:
4572 case SCF_TERR_WRONG_PG_TYPE:
4573 case SCF_TERR_WRONG_PROP_TYPE:
4574 case SCF_TERR_CARDINALITY_VIOLATION:
4575 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
4576 case SCF_TERR_RANGE_VIOLATION:
4577 case SCF_TERR_PROP_TYPE_MISMATCH:
4578 case SCF_TERR_VALUE_OUT_OF_RANGE:
4579 case SCF_TERR_INVALID_VALUE:
4580 case SCF_TERR_PG_PATTERN_CONFLICT:
4581 case SCF_TERR_PROP_PATTERN_CONFLICT:
4582 case SCF_TERR_GENERAL_REDEFINE:
4583 case SCF_TERR_INCLUDE_VALUES:
4584 return (dgettext(TEXT_DOMAIN,
4585 em_desc[err->te_type].em_actual));
4586 case SCF_TERR_MISSING_PROP:
4587 case SCF_TERR_PG_REDEFINE:
4588 case SCF_TERR_PG_PATTERN_INCOMPLETE:
4589 case SCF_TERR_PROP_PATTERN_INCOMPLETE:
4590 default:
4591 return (NULL);
4595 static const char *
4596 _get_tmpl_fmri_desc(scf_tmpl_error_t *err)
4598 switch (err->te_type) {
4599 case SCF_TERR_MISSING_PG:
4600 case SCF_TERR_WRONG_PG_TYPE:
4601 case SCF_TERR_MISSING_PROP:
4602 case SCF_TERR_WRONG_PROP_TYPE:
4603 case SCF_TERR_CARDINALITY_VIOLATION:
4604 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
4605 case SCF_TERR_RANGE_VIOLATION:
4606 case SCF_TERR_PG_REDEFINE:
4607 case SCF_TERR_PROP_TYPE_MISMATCH:
4608 case SCF_TERR_VALUE_OUT_OF_RANGE:
4609 case SCF_TERR_INVALID_VALUE:
4610 case SCF_TERR_PG_PATTERN_CONFLICT:
4611 case SCF_TERR_PROP_PATTERN_CONFLICT:
4612 case SCF_TERR_GENERAL_REDEFINE:
4613 case SCF_TERR_INCLUDE_VALUES:
4614 case SCF_TERR_PG_PATTERN_INCOMPLETE:
4615 case SCF_TERR_PROP_PATTERN_INCOMPLETE:
4616 return (dgettext(TEXT_DOMAIN, em_tmpl_fmri));
4617 default:
4618 return (NULL);
4622 static const char *
4623 _get_tmpl_pg_name_desc(scf_tmpl_error_t *err)
4625 switch (err->te_type) {
4626 case SCF_TERR_MISSING_PG:
4627 case SCF_TERR_WRONG_PG_TYPE:
4628 case SCF_TERR_MISSING_PROP:
4629 case SCF_TERR_WRONG_PROP_TYPE:
4630 case SCF_TERR_CARDINALITY_VIOLATION:
4631 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
4632 case SCF_TERR_RANGE_VIOLATION:
4633 case SCF_TERR_PG_REDEFINE:
4634 case SCF_TERR_PROP_TYPE_MISMATCH:
4635 case SCF_TERR_VALUE_OUT_OF_RANGE:
4636 case SCF_TERR_INVALID_VALUE:
4637 case SCF_TERR_PG_PATTERN_CONFLICT:
4638 case SCF_TERR_PROP_PATTERN_CONFLICT:
4639 case SCF_TERR_GENERAL_REDEFINE:
4640 case SCF_TERR_INCLUDE_VALUES:
4641 case SCF_TERR_PG_PATTERN_INCOMPLETE:
4642 case SCF_TERR_PROP_PATTERN_INCOMPLETE:
4643 return (dgettext(TEXT_DOMAIN, em_tmpl_pg_name));
4644 default:
4645 return (NULL);
4649 static const char *
4650 _get_tmpl_pg_type_desc(scf_tmpl_error_t *err)
4652 switch (err->te_type) {
4653 case SCF_TERR_MISSING_PG:
4654 case SCF_TERR_WRONG_PG_TYPE:
4655 case SCF_TERR_MISSING_PROP:
4656 case SCF_TERR_WRONG_PROP_TYPE:
4657 case SCF_TERR_CARDINALITY_VIOLATION:
4658 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
4659 case SCF_TERR_RANGE_VIOLATION:
4660 case SCF_TERR_PG_REDEFINE:
4661 case SCF_TERR_PROP_TYPE_MISMATCH:
4662 case SCF_TERR_VALUE_OUT_OF_RANGE:
4663 case SCF_TERR_INVALID_VALUE:
4664 case SCF_TERR_PG_PATTERN_CONFLICT:
4665 case SCF_TERR_PROP_PATTERN_CONFLICT:
4666 case SCF_TERR_GENERAL_REDEFINE:
4667 case SCF_TERR_INCLUDE_VALUES:
4668 case SCF_TERR_PROP_PATTERN_INCOMPLETE:
4669 case SCF_TERR_PG_PATTERN_INCOMPLETE:
4670 return (dgettext(TEXT_DOMAIN, em_tmpl_pg_type));
4671 default:
4672 return (NULL);
4676 static const char *
4677 _get_tmpl_prop_name_desc(scf_tmpl_error_t *err)
4679 switch (err->te_type) {
4680 case SCF_TERR_MISSING_PROP:
4681 case SCF_TERR_WRONG_PROP_TYPE:
4682 case SCF_TERR_CARDINALITY_VIOLATION:
4683 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
4684 case SCF_TERR_RANGE_VIOLATION:
4685 case SCF_TERR_PROP_TYPE_MISMATCH:
4686 case SCF_TERR_VALUE_OUT_OF_RANGE:
4687 case SCF_TERR_INVALID_VALUE:
4688 case SCF_TERR_PROP_PATTERN_CONFLICT:
4689 case SCF_TERR_INCLUDE_VALUES:
4690 case SCF_TERR_PROP_PATTERN_INCOMPLETE:
4691 return (dgettext(TEXT_DOMAIN, em_tmpl_prop_name));
4692 case SCF_TERR_MISSING_PG:
4693 case SCF_TERR_WRONG_PG_TYPE:
4694 case SCF_TERR_PG_REDEFINE:
4695 case SCF_TERR_PG_PATTERN_CONFLICT:
4696 case SCF_TERR_GENERAL_REDEFINE:
4697 case SCF_TERR_PG_PATTERN_INCOMPLETE:
4698 default:
4699 return (NULL);
4703 static const char *
4704 _get_tmpl_prop_type_desc(scf_tmpl_error_t *err)
4706 switch (err->te_type) {
4707 case SCF_TERR_MISSING_PROP:
4708 case SCF_TERR_WRONG_PROP_TYPE:
4709 case SCF_TERR_CARDINALITY_VIOLATION:
4710 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
4711 case SCF_TERR_RANGE_VIOLATION:
4712 case SCF_TERR_PROP_TYPE_MISMATCH:
4713 case SCF_TERR_VALUE_OUT_OF_RANGE:
4714 case SCF_TERR_INVALID_VALUE:
4715 case SCF_TERR_PROP_PATTERN_CONFLICT:
4716 case SCF_TERR_INCLUDE_VALUES:
4717 return (dgettext(TEXT_DOMAIN, em_tmpl_prop_type));
4718 case SCF_TERR_MISSING_PG:
4719 case SCF_TERR_WRONG_PG_TYPE:
4720 case SCF_TERR_PG_REDEFINE:
4721 case SCF_TERR_PG_PATTERN_CONFLICT:
4722 case SCF_TERR_GENERAL_REDEFINE:
4723 case SCF_TERR_PG_PATTERN_INCOMPLETE:
4724 case SCF_TERR_PROP_PATTERN_INCOMPLETE:
4725 default:
4726 return (NULL);
4730 static const char *
4731 _get_fmri_val(scf_tmpl_error_t *err)
4733 assert(err != NULL && err->te_errs != NULL &&
4734 err->te_errs->tes_fmri != NULL);
4735 return (err->te_errs->tes_fmri);
4738 static const char *
4739 _get_pg_name_val(scf_tmpl_error_t *err)
4741 assert(err != NULL);
4742 return (err->te_pg_name);
4745 static const char *
4746 _get_prop_name_val(scf_tmpl_error_t *err)
4748 assert(err != NULL);
4749 return (err->te_prop_name);
4752 static const char *
4753 _get_ev1_val(scf_tmpl_error_t *err)
4755 assert(err != NULL);
4756 return (err->te_ev1);
4759 static const char *
4760 _get_ev2_val(scf_tmpl_error_t *err)
4762 assert(err != NULL);
4763 return (err->te_ev2);
4766 static const char *
4767 _get_actual_val(scf_tmpl_error_t *err)
4769 assert(err != NULL);
4770 return (err->te_actual);
4773 static const char *
4774 _get_tmpl_fmri_val(scf_tmpl_error_t *err)
4776 assert(err != NULL);
4777 return (err->te_tmpl_fmri);
4780 static const char *
4781 _get_tmpl_pg_name_val(scf_tmpl_error_t *err)
4783 assert(err != NULL);
4784 return (err->te_tmpl_pg_name);
4787 static const char *
4788 _get_tmpl_pg_type_val(scf_tmpl_error_t *err)
4790 assert(err != NULL);
4791 return (err->te_tmpl_pg_type);
4794 static const char *
4795 _get_tmpl_prop_name_val(scf_tmpl_error_t *err)
4797 assert(err != NULL);
4798 return (err->te_tmpl_prop_name);
4801 static const char *
4802 _get_tmpl_prop_type_val(scf_tmpl_error_t *err)
4804 assert(err != NULL);
4805 return (err->te_tmpl_prop_type);
4809 * Templates error item retrival functions
4811 typedef const char *(*get_em)(scf_tmpl_error_t *);
4814 * if new items (lines) are added to the templates error messages,
4815 * new entries in this array (and new fuctions) will be required.
4817 static struct _tmpl_error_access {
4818 get_em get_desc;
4819 get_em get_val;
4820 } _tmpl_error_items[] = {
4821 { (get_em)_get_fmri_desc, (get_em)_get_fmri_val },
4822 { (get_em)_get_pg_name_desc, (get_em)_get_pg_name_val },
4823 { (get_em)_get_prop_name_desc, (get_em)_get_prop_name_val },
4824 { (get_em)_get_ev1_desc, (get_em)_get_ev1_val },
4825 { (get_em)_get_ev2_desc, (get_em)_get_ev2_val },
4826 { (get_em)_get_actual_desc, (get_em)_get_actual_val },
4827 { (get_em)_get_tmpl_fmri_desc, (get_em)_get_tmpl_fmri_val },
4828 { (get_em)_get_tmpl_pg_name_desc, (get_em)_get_tmpl_pg_name_val },
4829 { (get_em)_get_tmpl_pg_type_desc, (get_em)_get_tmpl_pg_type_val },
4830 { (get_em)_get_tmpl_prop_name_desc, (get_em)_get_tmpl_prop_name_val },
4831 { (get_em)_get_tmpl_prop_type_desc, (get_em)_get_tmpl_prop_type_val },
4832 { NULL }
4836 * Allocate a new scf_tmpl_error_t and add it to the errs list provided.
4837 * Returns NULL on failure. Sets scf_error():
4838 * SCF_ERROR_NO_MEMORY
4840 static scf_tmpl_error_t *
4841 _create_error(scf_tmpl_errors_t *errs)
4843 scf_tmpl_error_t *ret;
4844 scf_tmpl_error_t **saved_errs;
4846 assert(errs != NULL);
4847 ret = calloc(1, sizeof (scf_tmpl_error_t));
4848 if (ret == NULL) {
4849 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
4850 return (NULL);
4853 ret->te_errs = errs;
4855 assert(errs->tes_num_errs <= errs->tes_errs_size);
4856 if (errs->tes_num_errs == errs->tes_errs_size) {
4857 /* Time to grow the pointer array. */
4858 saved_errs = errs->tes_errs;
4859 errs->tes_errs = calloc(2 * errs->tes_errs_size,
4860 sizeof (scf_tmpl_error_t *));
4861 if (errs->tes_errs == NULL) {
4862 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
4863 errs->tes_errs = saved_errs;
4864 free(ret);
4865 return (NULL);
4867 (void) memcpy(errs->tes_errs, saved_errs, errs->tes_errs_size *
4868 sizeof (scf_tmpl_error_t *));
4869 errs->tes_errs_size = 2 * errs->tes_errs_size;
4870 free(saved_errs);
4873 errs->tes_errs[errs->tes_num_errs] = ret;
4874 errs->tes_num_errs++;
4876 return (ret);
4881 * If destroy_strings is set, scf_tmpl_errors_destroy will free the
4882 * strings in scf_tmpl_error_t entries.
4884 * Returns NULL on failure. Sets scf_error():
4885 * SCF_ERROR_NO_MEMORY
4887 scf_tmpl_errors_t *
4888 _scf_create_errors(const char *fmri, int destroy_strings)
4890 scf_tmpl_errors_t *ret;
4891 int errs_size = 20;
4893 assert(fmri != NULL);
4895 ret = calloc(1, sizeof (scf_tmpl_errors_t));
4896 if (ret == NULL) {
4897 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
4898 return (NULL);
4901 ret->tes_index = 0;
4902 ret->tes_num_errs = 0;
4903 if ((ret->tes_fmri = strdup(fmri)) == NULL) {
4904 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
4905 free(ret);
4906 return (NULL);
4909 ret->tes_prefix = strdup("");
4910 if (ret->tes_prefix == NULL) {
4911 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
4912 free((char *)ret->tes_fmri);
4913 free(ret);
4914 return (NULL);
4916 ret->tes_flag = destroy_strings;
4918 /* Make space for a few errors. */
4919 ret->tes_errs = calloc(errs_size, sizeof (scf_tmpl_error_t *));
4920 if (ret->tes_errs == NULL) {
4921 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
4922 free((char *)ret->tes_fmri);
4923 free((char *)ret->tes_prefix);
4924 free(ret);
4925 return (NULL);
4927 ret->tes_errs_size = errs_size;
4929 return (ret);
4933 * return 0 on success, if fails set scf_error() to:
4935 * SCF_ERROR_NO_MEMORY
4938 _scf_tmpl_error_set_prefix(scf_tmpl_errors_t *errs, const char *prefix)
4940 free((void *) errs->tes_prefix);
4941 if (prefix == NULL)
4942 errs->tes_prefix = strdup("");
4943 else
4944 errs->tes_prefix = strdup(prefix);
4945 if (errs->tes_prefix == NULL) {
4946 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
4947 return (-1);
4949 return (0);
4954 * Returns -1 on failure. Sets scf_error():
4955 * SCF_ERROR_NO_MEMORY
4958 _scf_tmpl_add_error(scf_tmpl_errors_t *errs, scf_tmpl_error_type_t type,
4959 const char *pg_name, const char *prop_name,
4960 const char *ev1, const char *ev2, const char *actual,
4961 const char *tmpl_fmri, const char *tmpl_pg_name, const char *tmpl_pg_type,
4962 const char *tmpl_prop_name, const char *tmpl_prop_type)
4964 scf_tmpl_error_t *err;
4966 assert(errs != NULL);
4967 assert(tmpl_fmri != NULL);
4969 err = _create_error(errs);
4970 if (err == NULL)
4971 return (-1);
4973 err->te_type = type;
4974 err->te_pg_name = pg_name;
4975 err->te_prop_name = prop_name;
4976 err->te_ev1 = ev1;
4977 err->te_ev2 = ev2;
4978 err->te_actual = actual;
4979 err->te_tmpl_fmri = tmpl_fmri;
4980 err->te_tmpl_pg_name = tmpl_pg_name;
4981 err->te_tmpl_pg_type = tmpl_pg_type;
4982 err->te_tmpl_prop_name = tmpl_prop_name;
4983 err->te_tmpl_prop_type = tmpl_prop_type;
4985 return (0);
4989 * returns an allocated string that must be freed with free()
4990 * string contains converted 64-bit integer value
4991 * flag set for signed values
4992 * if fails return NULL and set scf_error() to:
4993 * SCF_ERROR_NO_MEMORY
4995 static char *
4996 _val_to_string(uint64_t val, int flag)
4998 ssize_t sz = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH) + 1;
4999 char *buf;
5001 buf = malloc(sz);
5002 if (buf == NULL) {
5003 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
5004 return (NULL);
5007 if (flag == 0)
5008 (void) snprintf(buf, sz, "%" PRIu64, val);
5009 else
5010 (void) snprintf(buf, sz, "%" PRIi64, (int64_t)val);
5012 return (buf);
5016 * return 0 on success, -1 on failure.
5017 * set scf_error() to:
5018 * SCF_ERROR_BACKEND_ACCESS
5019 * SCF_ERROR_CONNECTION_BROKEN
5020 * SCF_ERROR_DELETED
5021 * SCF_ERROR_HANDLE_DESTROYED
5022 * SCF_ERROR_INTERNAL
5023 * SCF_ERROR_NO_MEMORY
5024 * SCF_ERROR_NO_RESOURCES
5025 * SCF_ERROR_NOT_BOUND
5026 * SCF_ERROR_PERMISSION_DENIED
5027 * SCF_ERROR_TEMPLATE_INVALID
5029 static int
5030 _add_tmpl_missing_pg_error(scf_tmpl_errors_t *errs, scf_pg_tmpl_t *t)
5032 char *ev1 = NULL;
5033 char *ev2 = NULL;
5034 char *t_fmri = NULL;
5035 char *t_pg_name = NULL;
5036 char *t_pg_type = NULL;
5038 if ((t_fmri = _scf_tmpl_get_fmri(t)) == NULL)
5039 return (-1);
5040 if (scf_tmpl_pg_name(t, &t_pg_name) == -1) {
5041 goto cleanup;
5043 if (scf_tmpl_pg_type(t, &t_pg_type) == -1) {
5044 goto cleanup;
5046 if ((ev1 = strdup(t_pg_name)) == NULL) {
5047 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
5048 goto cleanup;
5050 if ((ev2 = strdup(t_pg_type)) == NULL) {
5051 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
5052 goto cleanup;
5055 return (_scf_tmpl_add_error(errs, SCF_TERR_MISSING_PG, NULL, NULL, ev1,
5056 ev2, NULL, t_fmri, t_pg_name, t_pg_type, NULL, NULL));
5057 cleanup:
5058 free(ev1);
5059 free(ev2);
5060 free(t_fmri);
5061 free(t_pg_name);
5062 free(t_pg_type);
5063 return (-1);
5067 * return 0 on success, -1 on failure.
5068 * set scf_error() to:
5069 * SCF_ERROR_BACKEND_ACCESS
5070 * SCF_ERROR_CONNECTION_BROKEN
5071 * SCF_ERROR_DELETED
5072 * SCF_ERROR_HANDLE_DESTROYED
5073 * SCF_ERROR_INTERNAL
5074 * SCF_ERROR_NO_MEMORY
5075 * SCF_ERROR_NO_RESOURCES
5076 * SCF_ERROR_NOT_BOUND
5077 * SCF_ERROR_PERMISSION_DENIED
5078 * SCF_ERROR_TEMPLATE_INVALID
5080 static int
5081 _add_tmpl_wrong_pg_type_error(scf_tmpl_errors_t *errs, scf_pg_tmpl_t *t,
5082 scf_propertygroup_t *pg)
5084 char *pg_name = NULL;
5085 char *ev1 = NULL;
5086 char *actual = NULL;
5087 char *t_fmri = NULL;
5088 char *t_pg_name = NULL;
5089 char *t_pg_type = NULL;
5091 if ((t_fmri = _scf_tmpl_get_fmri(t)) == NULL)
5092 return (-1);
5093 if ((pg_name = _scf_get_pg_name(pg)) == NULL)
5094 goto cleanup;
5095 if ((actual = _scf_get_pg_type(pg)) == NULL)
5096 goto cleanup;
5097 if (scf_tmpl_pg_name(t, &t_pg_name) == -1) {
5098 goto cleanup;
5100 if (scf_tmpl_pg_type(t, &t_pg_type) == -1) {
5101 goto cleanup;
5103 if ((ev1 = strdup(t_pg_type)) == NULL) {
5104 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
5105 goto cleanup;
5108 return (_scf_tmpl_add_error(errs, SCF_TERR_WRONG_PG_TYPE, pg_name, NULL,
5109 ev1, NULL, actual, t_fmri, t_pg_name, t_pg_type, NULL, NULL));
5110 cleanup:
5111 free(pg_name);
5112 free(ev1);
5113 free(actual);
5114 free(t_fmri);
5115 free(t_pg_name);
5116 free(t_pg_type);
5117 return (-1);
5121 * return 0 on success, -1 on failure.
5122 * set scf_error() to:
5123 * SCF_ERROR_BACKEND_ACCESS
5124 * SCF_ERROR_CONNECTION_BROKEN
5125 * SCF_ERROR_DELETED
5126 * SCF_ERROR_HANDLE_DESTROYED
5127 * SCF_ERROR_INTERNAL
5128 * SCF_ERROR_NO_MEMORY
5129 * SCF_ERROR_NO_RESOURCES
5130 * SCF_ERROR_NOT_BOUND
5131 * SCF_ERROR_PERMISSION_DENIED
5132 * SCF_ERROR_TEMPLATE_INVALID
5134 static int
5135 _add_tmpl_missing_prop_error(scf_tmpl_errors_t *errs, scf_pg_tmpl_t *t,
5136 scf_propertygroup_t *pg, const scf_prop_tmpl_t *pt)
5138 char *pg_name = NULL;
5139 char *ev1 = NULL;
5140 char *t_fmri = NULL;
5141 char *t_pg_name = NULL;
5142 char *t_pg_type = NULL;
5143 char *t_prop_name = NULL;
5144 char *t_prop_type = NULL;
5146 if ((t_fmri = _scf_tmpl_get_fmri(t)) == NULL)
5147 return (-1);
5148 if ((pg_name = _scf_get_pg_name(pg)) == NULL)
5149 goto cleanup;
5150 if (scf_tmpl_pg_name(t, &t_pg_name) == -1) {
5151 goto cleanup;
5153 if (scf_tmpl_pg_type(t, &t_pg_type) == -1) {
5154 goto cleanup;
5156 if (scf_tmpl_prop_name(pt, &t_prop_name) == -1) {
5157 goto cleanup;
5159 t_prop_type = _scf_read_tmpl_prop_type_as_string(pt);
5160 if (t_prop_type != NULL && t_prop_type[0] == '\0') {
5161 free(t_prop_type);
5162 t_prop_type = NULL;
5163 } else if (t_prop_type == NULL) {
5164 goto cleanup;
5166 if (t_prop_type == NULL)
5167 if ((t_prop_type = strdup(SCF_TMPL_WILDCARD)) == NULL) {
5168 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
5169 goto cleanup;
5171 if ((ev1 = strdup(t_prop_name)) == NULL) {
5172 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
5173 goto cleanup;
5176 return (_scf_tmpl_add_error(errs, SCF_TERR_MISSING_PROP, pg_name, NULL,
5177 ev1, NULL, NULL, t_fmri, t_pg_name, t_pg_type, t_prop_name,
5178 t_prop_type));
5179 cleanup:
5180 free(pg_name);
5181 free(ev1);
5182 free(t_fmri);
5183 free(t_pg_name);
5184 free(t_pg_type);
5185 free(t_prop_name);
5186 free(t_prop_type);
5187 return (-1);
5191 * return 0 on success, -1 on failure.
5192 * set scf_error() to:
5193 * SCF_ERROR_BACKEND_ACCESS
5194 * SCF_ERROR_CONNECTION_BROKEN
5195 * SCF_ERROR_DELETED
5196 * SCF_ERROR_HANDLE_DESTROYED
5197 * SCF_ERROR_INTERNAL
5198 * SCF_ERROR_NO_MEMORY
5199 * SCF_ERROR_NO_RESOURCES
5200 * SCF_ERROR_NOT_BOUND
5201 * SCF_ERROR_PERMISSION_DENIED
5202 * SCF_ERROR_TEMPLATE_INVALID
5204 static int
5205 _add_tmpl_wrong_prop_type_error(scf_tmpl_errors_t *errs,
5206 scf_propertygroup_t *pg, const scf_prop_tmpl_t *pt, scf_property_t *prop)
5208 char *pg_name = NULL;
5209 char *prop_name = NULL;
5210 char *ev1 = NULL;
5211 char *actual = NULL;
5212 char *t_fmri = NULL;
5213 char *t_pg_name = NULL;
5214 char *t_pg_type = NULL;
5215 char *t_prop_name = NULL;
5216 char *t_prop_type = NULL;
5218 if ((t_fmri = _scf_tmpl_get_fmri(pt->prt_t)) == NULL)
5219 return (-1);
5220 if ((pg_name = _scf_get_pg_name(pg)) == NULL)
5221 goto cleanup;
5222 if ((prop_name = _scf_get_prop_name(prop)) == NULL)
5223 goto cleanup;
5224 if ((actual = _scf_get_prop_type(prop)) == NULL)
5225 goto cleanup;
5226 if (scf_tmpl_pg_name(pt->prt_t, &t_pg_name) == -1) {
5227 goto cleanup;
5229 if (scf_tmpl_pg_type(pt->prt_t, &t_pg_type) == -1) {
5230 goto cleanup;
5232 if (scf_tmpl_prop_name(pt, &t_prop_name) == -1) {
5233 goto cleanup;
5235 t_prop_type = _scf_read_tmpl_prop_type_as_string(pt);
5236 if (t_prop_type != NULL && t_prop_type[0] == '\0') {
5237 free(t_prop_type);
5238 t_prop_type = NULL;
5239 } else if (t_prop_type == NULL) {
5240 goto cleanup;
5242 if (t_prop_type == NULL)
5243 if ((t_prop_type = strdup(SCF_TMPL_WILDCARD)) == NULL) {
5244 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
5245 goto cleanup;
5247 if ((ev1 = strdup(t_prop_type)) == NULL) {
5248 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
5249 goto cleanup;
5252 return (_scf_tmpl_add_error(errs, SCF_TERR_WRONG_PROP_TYPE, pg_name,
5253 prop_name, ev1, NULL, actual, t_fmri, t_pg_name, t_pg_type,
5254 t_prop_name, t_prop_type));
5255 cleanup:
5256 free(pg_name);
5257 free(prop_name);
5258 free(ev1);
5259 free(actual);
5260 free(t_fmri);
5261 free(t_pg_name);
5262 free(t_pg_type);
5263 free(t_prop_name);
5264 free(t_prop_type);
5265 return (-1);
5269 * return 0 on success, -1 on failure.
5270 * set scf_error() to:
5271 * SCF_ERROR_BACKEND_ACCESS
5272 * SCF_ERROR_CONNECTION_BROKEN
5273 * SCF_ERROR_DELETED
5274 * SCF_ERROR_HANDLE_DESTROYED
5275 * SCF_ERROR_INTERNAL
5276 * SCF_ERROR_NO_MEMORY
5277 * SCF_ERROR_NO_RESOURCES
5278 * SCF_ERROR_NOT_BOUND
5279 * SCF_ERROR_PERMISSION_DENIED
5280 * SCF_ERROR_TEMPLATE_INVALID
5282 static int
5283 _add_tmpl_count_error(scf_tmpl_errors_t *errs, scf_tmpl_error_type_t type,
5284 scf_propertygroup_t *pg, const scf_prop_tmpl_t *pt, scf_property_t *prop,
5285 uint64_t count, uint64_t *min, uint64_t *max)
5287 char *pg_name = NULL;
5288 char *prop_name = NULL;
5289 char *s_min = NULL;
5290 char *s_max = NULL;
5291 char *num = NULL;
5292 char *t_fmri = NULL;
5293 char *t_pg_name = NULL;
5294 char *t_pg_type = NULL;
5295 char *t_prop_name = NULL;
5296 char *t_prop_type = NULL;
5298 if ((t_fmri = _scf_tmpl_get_fmri(pt->prt_t)) == NULL)
5299 return (-1);
5300 switch (type) {
5301 case SCF_TERR_RANGE_VIOLATION:
5302 case SCF_TERR_CARDINALITY_VIOLATION:
5303 if ((pg_name = _scf_get_pg_name(pg)) == NULL)
5304 goto cleanup;
5305 if ((prop_name = _scf_get_prop_name(prop)) == NULL)
5306 goto cleanup;
5307 break;
5308 case SCF_TERR_VALUE_OUT_OF_RANGE:
5309 /* keep pg_name = NULL and prop_name = NULL */
5310 break;
5312 if (scf_tmpl_pg_name(pt->prt_t, &t_pg_name) == -1) {
5313 goto cleanup;
5315 if (scf_tmpl_pg_type(pt->prt_t, &t_pg_type) == -1) {
5316 goto cleanup;
5318 if (scf_tmpl_prop_name(pt, &t_prop_name) == -1) {
5319 goto cleanup;
5321 t_prop_type = _scf_read_tmpl_prop_type_as_string(pt);
5322 if (t_prop_type != NULL && t_prop_type[0] == '\0') {
5323 free(t_prop_type);
5324 t_prop_type = NULL;
5325 } else if (t_prop_type == NULL) {
5326 goto cleanup;
5328 if (t_prop_type == NULL)
5329 if ((t_prop_type = strdup(SCF_TMPL_WILDCARD)) == NULL) {
5330 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
5331 goto cleanup;
5333 if (min == NULL) {
5334 if ((s_min = strdup("")) == NULL) {
5335 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
5336 goto cleanup;
5338 } else {
5339 if ((s_min = _val_to_string(*min, 0)) == NULL) {
5340 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
5341 goto cleanup;
5344 if (max == NULL) {
5345 if ((s_max = strdup("")) == NULL) {
5346 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
5347 goto cleanup;
5349 } else {
5350 if ((s_max = _val_to_string(*max, 0)) == NULL) {
5351 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
5352 goto cleanup;
5355 if ((num = _val_to_string(count, 0)) == NULL) {
5356 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
5357 goto cleanup;
5360 return (_scf_tmpl_add_error(errs, type, pg_name, prop_name, s_min,
5361 s_max, num, t_fmri, t_pg_name, t_pg_type, t_prop_name,
5362 t_prop_type));
5363 cleanup:
5364 free(pg_name);
5365 free(prop_name);
5366 free(s_min);
5367 free(s_max);
5368 free(num);
5369 free(t_fmri);
5370 free(t_pg_name);
5371 free(t_pg_type);
5372 free(t_prop_name);
5373 free(t_prop_type);
5374 return (-1);
5378 * return 0 on success, -1 on failure.
5379 * set scf_error() to:
5380 * SCF_ERROR_BACKEND_ACCESS
5381 * SCF_ERROR_CONNECTION_BROKEN
5382 * SCF_ERROR_DELETED
5383 * SCF_ERROR_HANDLE_DESTROYED
5384 * SCF_ERROR_INTERNAL
5385 * SCF_ERROR_NO_MEMORY
5386 * SCF_ERROR_NO_RESOURCES
5387 * SCF_ERROR_NOT_BOUND
5388 * SCF_ERROR_PERMISSION_DENIED
5389 * SCF_ERROR_TEMPLATE_INVALID
5391 static int
5392 _add_tmpl_constraint_error(scf_tmpl_errors_t *errs, scf_tmpl_error_type_t type,
5393 scf_propertygroup_t *pg, const scf_prop_tmpl_t *pt, scf_property_t *prop,
5394 scf_value_t *val)
5396 scf_type_t val_type;
5397 char *pg_name = NULL;
5398 char *prop_name = NULL;
5399 char *value = NULL;
5400 char *t_fmri = NULL;
5401 char *t_pg_name = NULL;
5402 char *t_pg_type = NULL;
5403 char *t_prop_name = NULL;
5404 char *t_prop_type = NULL;
5406 if ((t_fmri = _scf_tmpl_get_fmri(pt->prt_t)) == NULL)
5407 return (-1);
5408 switch (type) {
5409 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
5410 if ((pg_name = _scf_get_pg_name(pg)) == NULL)
5411 goto cleanup;
5412 if ((prop_name = _scf_get_prop_name(prop)) == NULL)
5413 goto cleanup;
5414 /*FALLTHROUGH*/
5415 case SCF_TERR_INVALID_VALUE:
5416 /* keep pg_name = NULL and prop_name = NULL */
5417 if ((value = _scf_value_get_as_string(val)) == NULL)
5418 goto cleanup;
5419 break;
5420 case SCF_TERR_PROP_TYPE_MISMATCH:
5421 /* keep pg_name = NULL and prop_name = NULL */
5422 /* use value for value type */
5423 val_type = scf_value_type(val);
5424 if ((value = strdup(scf_type_to_string(val_type))) ==
5425 NULL) {
5426 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
5427 goto cleanup;
5429 break;
5431 if (scf_tmpl_pg_name(pt->prt_t, &t_pg_name) == -1) {
5432 goto cleanup;
5434 if (scf_tmpl_pg_type(pt->prt_t, &t_pg_type) == -1) {
5435 goto cleanup;
5437 if (scf_tmpl_prop_name(pt, &t_prop_name) == -1) {
5438 goto cleanup;
5440 t_prop_type = _scf_read_tmpl_prop_type_as_string(pt);
5441 if (t_prop_type != NULL && t_prop_type[0] == '\0') {
5442 free(t_prop_type);
5443 t_prop_type = NULL;
5444 } else if (t_prop_type == NULL) {
5445 goto cleanup;
5447 if (t_prop_type == NULL)
5448 if ((t_prop_type = strdup(SCF_TMPL_WILDCARD)) == NULL) {
5449 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
5450 goto cleanup;
5453 return (_scf_tmpl_add_error(errs, type, pg_name, prop_name, NULL, NULL,
5454 value, t_fmri, t_pg_name, t_pg_type, t_prop_name, t_prop_type));
5455 cleanup:
5456 assert(scf_error() != SCF_ERROR_NOT_SET);
5457 free(pg_name);
5458 free(prop_name);
5459 free(value);
5460 free(t_fmri);
5461 free(t_pg_name);
5462 free(t_pg_type);
5463 free(t_prop_name);
5464 free(t_prop_type);
5465 return (-1);
5469 * return 0 on success, -1 on failure.
5470 * set scf_error() to:
5471 * SCF_ERROR_BACKEND_ACCESS
5472 * SCF_ERROR_CONNECTION_BROKEN
5473 * SCF_ERROR_DELETED
5474 * SCF_ERROR_HANDLE_DESTROYED
5475 * SCF_ERROR_INTERNAL
5476 * SCF_ERROR_NO_MEMORY
5477 * SCF_ERROR_NO_RESOURCES
5478 * SCF_ERROR_NOT_BOUND
5479 * SCF_ERROR_PERMISSION_DENIED
5480 * SCF_ERROR_TEMPLATE_INVALID
5482 static int
5483 _add_tmpl_int_error(scf_tmpl_errors_t *errs, scf_tmpl_error_type_t type,
5484 scf_propertygroup_t *pg, const scf_prop_tmpl_t *pt, scf_property_t *prop,
5485 int64_t val, int64_t *min, int64_t *max)
5487 char *pg_name = NULL;
5488 char *prop_name = NULL;
5489 char *s_min = NULL;
5490 char *s_max = NULL;
5491 char *value = NULL;
5492 char *t_fmri = NULL;
5493 char *t_pg_name = NULL;
5494 char *t_pg_type = NULL;
5495 char *t_prop_name = NULL;
5496 char *t_prop_type = NULL;
5498 if ((t_fmri = _scf_tmpl_get_fmri(pt->prt_t)) == NULL)
5499 return (-1);
5501 switch (type) {
5502 case SCF_TERR_RANGE_VIOLATION:
5503 if ((pg_name = _scf_get_pg_name(pg)) == NULL)
5504 goto cleanup;
5505 if ((prop_name = _scf_get_prop_name(prop)) == NULL)
5506 goto cleanup;
5507 break;
5508 case SCF_TERR_VALUE_OUT_OF_RANGE:
5509 /* keep pg_name = NULL and prop_name = NULL */
5510 break;
5512 if (scf_tmpl_pg_name(pt->prt_t, &t_pg_name) == -1) {
5513 goto cleanup;
5515 if (scf_tmpl_pg_type(pt->prt_t, &t_pg_type) == -1) {
5516 goto cleanup;
5518 if (scf_tmpl_prop_name(pt, &t_prop_name) == -1) {
5519 goto cleanup;
5521 t_prop_type = _scf_read_tmpl_prop_type_as_string(pt);
5522 if (t_prop_type != NULL && t_prop_type[0] == '\0') {
5523 free(t_prop_type);
5524 t_prop_type = NULL;
5525 } else if (t_prop_type == NULL) {
5526 goto cleanup;
5528 if (t_prop_type == NULL)
5529 if ((t_prop_type = strdup(SCF_TMPL_WILDCARD)) == NULL) {
5530 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
5531 goto cleanup;
5533 if (min == NULL) {
5534 if ((s_min = strdup("")) == NULL) {
5535 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
5536 goto cleanup;
5538 } else {
5539 if ((s_min = _val_to_string(*((uint64_t *)min), 1)) == NULL) {
5540 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
5541 goto cleanup;
5544 if (max == NULL) {
5545 if ((s_max = strdup("")) == NULL) {
5546 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
5547 goto cleanup;
5549 } else {
5550 if ((s_max = _val_to_string(*((uint64_t *)max), 1)) == NULL) {
5551 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
5552 goto cleanup;
5555 if ((value = _val_to_string((uint64_t)val, 1)) == NULL) {
5556 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
5557 goto cleanup;
5560 return (_scf_tmpl_add_error(errs, type, pg_name, prop_name, s_min,
5561 s_max, value, t_fmri, t_pg_name, t_pg_type, t_prop_name,
5562 t_prop_type));
5563 cleanup:
5564 free(pg_name);
5565 free(prop_name);
5566 free(s_min);
5567 free(s_max);
5568 free(value);
5569 free(t_fmri);
5570 free(t_pg_name);
5571 free(t_pg_type);
5572 free(t_prop_name);
5573 free(t_prop_type);
5574 return (-1);
5578 * return 0 on success, -1 on failure.
5579 * set scf_error() to:
5580 * SCF_ERROR_BACKEND_ACCESS
5581 * SCF_ERROR_CONNECTION_BROKEN
5582 * SCF_ERROR_DELETED
5583 * SCF_ERROR_HANDLE_DESTROYED
5584 * SCF_ERROR_INTERNAL
5585 * SCF_ERROR_NO_MEMORY
5586 * SCF_ERROR_NO_RESOURCES
5587 * SCF_ERROR_NOT_BOUND
5588 * SCF_ERROR_PERMISSION_DENIED
5589 * SCF_ERROR_TEMPLATE_INVALID
5591 static int
5592 _add_tmpl_pg_redefine_error(scf_tmpl_errors_t *errs, scf_pg_tmpl_t *t,
5593 scf_pg_tmpl_t *r)
5595 char *ev1 = NULL;
5596 char *ev2 = NULL;
5597 char *t_fmri = NULL;
5598 char *t_pg_name = NULL;
5599 char *t_pg_type = NULL;
5601 if ((t_fmri = _scf_tmpl_get_fmri(r)) == NULL)
5602 return (-1);
5603 if (scf_tmpl_pg_name(r, &t_pg_name) == -1) {
5604 goto cleanup;
5606 if (scf_tmpl_pg_type(r, &t_pg_type) == -1) {
5607 goto cleanup;
5609 if (scf_tmpl_pg_name(t, &ev1) == -1) {
5610 goto cleanup;
5612 if (scf_tmpl_pg_type(t, &ev2) == -1) {
5613 goto cleanup;
5616 return (_scf_tmpl_add_error(errs, SCF_TERR_PG_REDEFINE, NULL, NULL,
5617 ev1, ev2, NULL, t_fmri, t_pg_name, t_pg_type, NULL, NULL));
5618 cleanup:
5619 free(ev1);
5620 free(ev2);
5621 free(t_fmri);
5622 free(t_pg_name);
5623 free(t_pg_type);
5624 return (-1);
5628 * return 0 if value is within count ranges constraint.
5629 * return -1 otherwise
5631 static int
5632 _check_count_ranges(scf_count_ranges_t *cr, uint64_t v)
5634 int i;
5636 for (i = 0; i < cr->scr_num_ranges; ++i) {
5637 if (v >= cr->scr_min[i] &&
5638 v <= cr->scr_max[i]) {
5639 /* value is within ranges constraint */
5640 return (0);
5643 return (-1);
5647 * return 0 if value is within count ranges constraint.
5648 * return -1 otherwise
5650 static int
5651 _check_int_ranges(scf_int_ranges_t *ir, int64_t v)
5653 int i;
5655 for (i = 0; i < ir->sir_num_ranges; ++i) {
5656 if (v >= ir->sir_min[i] &&
5657 v <= ir->sir_max[i]) {
5658 /* value is within integer ranges constraint */
5659 return (0);
5662 return (-1);
5666 * int _value_in_constraint()
5668 * Checks whether the supplied value violates any of the constraints
5669 * specified in the supplied property template. If it does, an appropriate
5670 * error is appended to "errs". pg and prop, if supplied, are used to
5671 * augment the information in the error. Returns 0 on success.
5673 * Returns -1 on failure. Sets scf_error():
5674 * SCF_ERROR_BACKEND_ACCESS
5675 * SCF_ERROR_CONNECTION_BROKEN
5676 * SCF_ERROR_DELETED
5677 * SCF_ERROR_HANDLE_DESTROYED
5678 * SCF_ERROR_INTERNAL
5679 * SCF_ERROR_INVALID_ARGUMENT
5680 * SCF_ERROR_NO_MEMORY
5681 * SCF_ERROR_NO_RESOURCES
5682 * SCF_ERROR_NOT_BOUND
5683 * SCF_ERROR_PERMISSION_DENIED
5684 * SCF_ERROR_TEMPLATE_INVALID
5686 static int
5687 _value_in_constraint(scf_propertygroup_t *pg, scf_property_t *prop,
5688 const scf_prop_tmpl_t *pt, scf_value_t *value, scf_tmpl_errors_t *errs)
5690 scf_type_t type, tmpl_type;
5691 scf_values_t vals;
5692 scf_tmpl_error_type_t terr_type;
5693 uint64_t v_count;
5694 int64_t v_int;
5695 char *vstr;
5696 ssize_t sz = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH) + 1;
5697 ssize_t ret = 0;
5698 char **constraints;
5699 int n = 0;
5700 int r;
5701 int err_flag = 0;
5702 scf_count_ranges_t cr;
5703 scf_int_ranges_t ir;
5705 type = scf_value_type(value);
5706 if (type == SCF_TYPE_INVALID) {
5707 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
5708 return (-1);
5711 /* Check if template type matches value type. */
5712 if (scf_tmpl_prop_type(pt, &tmpl_type) == -1) {
5713 if (scf_error() != SCF_ERROR_NOT_FOUND)
5714 /* type is not wildcarded */
5715 return (-1);
5716 } else if (tmpl_type != type) {
5717 if (errs != NULL) {
5718 if (pg == NULL && prop == NULL) {
5719 if (_add_tmpl_constraint_error(errs,
5720 SCF_TERR_PROP_TYPE_MISMATCH, NULL, pt,
5721 NULL, value) == -1)
5722 return (-1);
5725 return (1);
5728 /* Numeric values should be checked against any range constraints. */
5729 switch (type) {
5730 case SCF_TYPE_COUNT:
5731 r = scf_value_get_count(value, &v_count);
5732 assert(r == 0);
5734 if (scf_tmpl_value_count_range_constraints(pt, &cr) != 0) {
5735 if (scf_error() == SCF_ERROR_NOT_FOUND)
5736 break;
5737 if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED)
5738 (void) scf_set_error(
5739 SCF_ERROR_TEMPLATE_INVALID);
5740 return (-1);
5741 } else {
5742 if (_check_count_ranges(&cr, v_count) == 0) {
5743 /* value is within ranges constraint */
5744 scf_count_ranges_destroy(&cr);
5745 return (0);
5747 scf_count_ranges_destroy(&cr);
5751 * If we get here, we have a possible constraint
5752 * violation.
5754 err_flag |= 0x1; /* RANGE_VIOLATION, count */
5755 break;
5756 case SCF_TYPE_INTEGER:
5757 if (scf_value_get_integer(value, &v_int) != 0)
5758 assert(0);
5759 if (scf_tmpl_value_int_range_constraints(pt, &ir) != 0) {
5760 if (scf_error() == SCF_ERROR_NOT_FOUND)
5761 break;
5762 if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
5763 (void) scf_set_error(
5764 SCF_ERROR_TEMPLATE_INVALID);
5765 return (-1);
5766 } else {
5767 if (_check_int_ranges(&ir, v_int) == 0) {
5768 /* value is within ranges constraint */
5769 scf_int_ranges_destroy(&ir);
5770 return (0);
5772 scf_int_ranges_destroy(&ir);
5775 * If we get here, we have a possible constraint
5776 * violation.
5778 err_flag |= 0x2; /* RANGE_VIOLATION, integer */
5779 break;
5780 default:
5781 break;
5784 vstr = malloc(sz);
5785 if (vstr == NULL) {
5786 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
5787 return (-1);
5791 * If a set of names is provided, confirm value has one of
5792 * those names.
5794 if (scf_tmpl_value_name_constraints(pt, &vals) != 0) {
5795 free(vstr);
5796 if (scf_error() != SCF_ERROR_NOT_FOUND) {
5797 return (-1);
5799 } else {
5800 r = scf_value_get_as_string_typed(value, type, vstr, sz);
5803 * All errors (INVALID_ARGUMENT, NOT_SET, TYPE_MISMATCH)
5804 * should be impossible or already caught above.
5806 assert(r > 0);
5808 constraints = vals.values.v_astring;
5809 for (n = 0; constraints[n] != NULL; ++n) {
5810 if (strcmp(constraints[n], vstr) == 0) {
5811 /* value is within constraint */
5812 scf_values_destroy(&vals);
5813 free(vstr);
5814 return (0);
5817 /* if we get here, we have a constraint violation */
5818 err_flag |= 0x4; /* CONSTRAINT_VIOLATED */
5819 scf_values_destroy(&vals);
5820 free(vstr);
5822 if (err_flag != 0)
5823 ret = 1;
5824 /* register the errors found */
5825 if (ret == 1 && errs != NULL) {
5826 if ((err_flag & 0x1) == 0x1) {
5828 * Help make the error more human-friendly. If
5829 * pg and prop are provided, we know we're
5830 * validating repository data. If they're not,
5831 * we're validating a potentially hypothetical
5832 * value.
5834 if (pg == NULL && prop == NULL)
5835 terr_type = SCF_TERR_VALUE_OUT_OF_RANGE;
5836 else
5837 terr_type = SCF_TERR_RANGE_VIOLATION;
5838 if (_add_tmpl_count_error(errs, terr_type, pg, pt,
5839 prop, v_count, 0, 0) == -1)
5840 ret = -1;
5842 if ((err_flag & 0x2) == 0x2) {
5843 if (pg == NULL && prop == NULL)
5844 terr_type = SCF_TERR_VALUE_OUT_OF_RANGE;
5845 else
5846 terr_type = SCF_TERR_RANGE_VIOLATION;
5847 if (_add_tmpl_int_error(errs, terr_type, pg, pt, prop,
5848 v_int, 0, 0) == -1)
5849 ret = -1;
5851 if ((err_flag & 0x4) == 0x4) {
5852 if (pg == NULL && prop == NULL)
5853 terr_type = SCF_TERR_INVALID_VALUE;
5854 else
5855 terr_type = SCF_TERR_VALUE_CONSTRAINT_VIOLATED;
5856 if (_add_tmpl_constraint_error(errs, terr_type, pg,
5857 pt, prop, value) == -1)
5858 ret = -1;
5861 return (ret);
5865 * Returns -1 on failure. Sets scf_error():
5866 * SCF_ERROR_BACKEND_ACCESS
5867 * SCF_ERROR_CONNECTION_BROKEN
5868 * SCF_ERROR_DELETED
5869 * SCF_ERROR_HANDLE_DESTROYED
5870 * SCF_ERROR_INTERNAL
5871 * SCF_ERROR_INVALID_ARGUMENT
5872 * SCF_ERROR_NO_MEMORY
5873 * SCF_ERROR_NO_RESOURCES
5874 * SCF_ERROR_NOT_BOUND
5875 * SCF_ERROR_PERMISSION_DENIED
5876 * SCF_ERROR_TEMPLATE_INVALID
5879 scf_tmpl_value_in_constraint(const scf_prop_tmpl_t *pt, scf_value_t *value,
5880 scf_tmpl_errors_t **errs)
5882 scf_tmpl_errors_t *e = NULL;
5884 if (errs != NULL) {
5885 char *fmri;
5887 if ((fmri = _scf_tmpl_get_fmri(pt->prt_t)) == NULL)
5888 return (-1);
5889 *errs = _scf_create_errors(fmri, 1);
5890 free(fmri);
5891 if (*errs == NULL)
5892 return (-1);
5893 e = *errs;
5896 return (_value_in_constraint(NULL, NULL, pt, value, e));
5899 scf_tmpl_error_t *
5900 scf_tmpl_next_error(scf_tmpl_errors_t *errs)
5902 if (errs->tes_index < errs->tes_num_errs) {
5903 assert(errs->tes_errs[errs->tes_index] != NULL);
5904 return (errs->tes_errs[errs->tes_index++]);
5905 } else {
5906 return (NULL);
5910 void
5911 scf_tmpl_reset_errors(scf_tmpl_errors_t *errs)
5913 errs->tes_index = 0;
5917 scf_tmpl_strerror(scf_tmpl_error_t *err, char *s, size_t n, int flag)
5919 const char *str;
5920 int i;
5921 int ret = -1;
5922 int nsz = 0; /* err msg length */
5923 int sz = n; /* available buffer size */
5924 char *buf = s; /* where to append in buffer */
5925 char *s0 = (flag == SCF_TMPL_STRERROR_HUMAN) ? ":\n\t" : ": ";
5926 char *s1 = (flag == SCF_TMPL_STRERROR_HUMAN) ? "\n\t" : "; ";
5927 char *sep = s0;
5928 const char *val;
5930 /* prefix */
5931 if (err->te_errs->tes_prefix != NULL) {
5932 ret = snprintf(buf, sz, "%s", dgettext(TEXT_DOMAIN,
5933 err->te_errs->tes_prefix));
5934 nsz += ret;
5935 sz = (sz - ret) > 0 ? sz - ret : 0;
5936 buf = (sz > 0) ? s + nsz : NULL;
5938 /* error message */
5939 ret = snprintf(buf, sz, "%s", dgettext(TEXT_DOMAIN,
5940 em_desc[err->te_type].em_msg));
5941 nsz += ret;
5942 sz = (sz - ret) > 0 ? sz - ret : 0;
5943 buf = (sz > 0) ? s + nsz : NULL;
5945 for (i = 0; _tmpl_error_items[i].get_desc != NULL; ++i) {
5946 if ((str = _tmpl_error_items[i].get_desc(err)) == NULL)
5947 /* no item to print */
5948 continue;
5949 val = _tmpl_error_items[i].get_val(err);
5950 ret = snprintf(buf, sz, "%s%s=\"%s\"", sep, str,
5951 (val == NULL) ? "" : val);
5952 nsz += ret;
5953 sz = (sz - ret) > 0 ? sz - ret : 0;
5954 buf = (sz > 0) ? s + nsz : NULL;
5955 sep = s1;
5957 return (nsz);
5961 * return 0 on success, -1 on failure.
5962 * set scf_error() to:
5963 * SCF_ERROR_BACKEND_ACCESS
5964 * SCF_ERROR_CONNECTION_BROKEN
5965 * SCF_ERROR_DELETED
5966 * SCF_ERROR_HANDLE_DESTROYED
5967 * SCF_ERROR_INTERNAL
5968 * SCF_ERROR_NO_MEMORY
5969 * SCF_ERROR_NO_RESOURCES
5970 * SCF_ERROR_NOT_BOUND
5971 * SCF_ERROR_PERMISSION_DENIED
5972 * SCF_ERROR_TEMPLATE_INVALID
5974 static int
5975 _validate_cardinality(scf_propertygroup_t *pg, scf_prop_tmpl_t *pt,
5976 scf_property_t *prop, scf_tmpl_errors_t *errs)
5978 uint64_t min, max;
5979 scf_handle_t *h;
5980 scf_iter_t *iter = NULL;
5981 scf_value_t *val = NULL;
5982 int count = 0;
5983 int ret = -1;
5984 int r;
5986 if (scf_tmpl_prop_cardinality(pt, &min, &max) != 0) {
5987 if (scf_error() == SCF_ERROR_NOT_FOUND)
5988 return (0);
5989 else
5990 return (-1);
5993 /* Any number of values permitted. Just return success. */
5994 if (min == 0 && max == UINT64_MAX) {
5995 return (0);
5998 h = scf_property_handle(prop);
5999 if (h == NULL) {
6000 assert(scf_error() == SCF_ERROR_HANDLE_DESTROYED);
6001 goto cleanup;
6004 iter = scf_iter_create(h);
6005 val = scf_value_create(h);
6006 if (iter == NULL || val == NULL) {
6007 if (ismember(scf_error(), errors_server)) {
6008 goto cleanup;
6009 } else {
6010 assert(0);
6011 abort();
6015 if (scf_iter_property_values(iter, prop) != 0) {
6016 if (ismember(scf_error(), errors_server)) {
6017 goto cleanup;
6018 } else {
6019 assert(0);
6020 abort();
6024 while ((r = scf_iter_next_value(iter, val)) == 1)
6025 count++;
6027 if (r < 0) {
6028 if (ismember(scf_error(), errors_server)) {
6029 goto cleanup;
6030 } else {
6031 assert(0);
6032 abort();
6036 if (count < min || count > max)
6037 if (_add_tmpl_count_error(errs, SCF_TERR_CARDINALITY_VIOLATION,
6038 pg, pt, prop, (uint64_t)count, &min, &max) == -1)
6039 goto cleanup;
6041 ret = 0;
6043 cleanup:
6044 scf_iter_destroy(iter);
6045 scf_value_destroy(val);
6046 return (ret);
6050 * Returns -1 on error. Sets scf_error():
6051 * SCF_ERROR_BACKEND_ACCESS
6052 * SCF_ERROR_CONNECTION_BROKEN
6053 * SCF_ERROR_DELETED
6054 * SCF_ERROR_HANDLE_DESTROYED
6055 * SCF_ERROR_INTERNAL
6056 * SCF_ERROR_NO_MEMORY
6057 * SCF_ERROR_NO_RESOURCES
6058 * SCF_ERROR_NOT_BOUND
6059 * SCF_ERROR_PERMISSION_DENIED
6060 * SCF_ERROR_TEMPLATE_INVALID
6062 static int
6063 _check_property(scf_prop_tmpl_t *pt, scf_propertygroup_t *pg,
6064 scf_property_t *prop, scf_tmpl_errors_t *errs)
6066 scf_type_t tmpl_type;
6067 uint8_t required;
6068 scf_handle_t *h;
6069 scf_iter_t *iter = NULL;
6070 scf_value_t *val = NULL;
6071 int r;
6072 int ret = -1;
6074 h = scf_pg_handle(pg);
6075 if (h == NULL) {
6076 assert(scf_error() == SCF_ERROR_HANDLE_DESTROYED);
6077 return (-1);
6080 iter = scf_iter_create(h);
6081 val = scf_value_create(h);
6082 if (iter == NULL || val == NULL) {
6083 if (ismember(scf_error(), errors_server)) {
6084 scf_iter_destroy(iter);
6085 scf_value_destroy(val);
6086 return (-1);
6087 } else {
6088 assert(0);
6089 abort();
6093 if (scf_tmpl_prop_required(pt, &required) != 0)
6094 goto cleanup;
6096 /* Check type */
6097 if (scf_tmpl_prop_type(pt, &tmpl_type) == -1) {
6098 if (scf_error() != SCF_ERROR_NOT_FOUND) {
6099 goto cleanup;
6100 } else if (required) {
6101 /* If required, type must be specified. */
6102 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
6103 goto cleanup;
6105 } else if (scf_property_is_type(prop, tmpl_type) != 0) {
6106 if (ismember(scf_error(), errors_server)) {
6107 goto cleanup;
6108 } else switch (scf_error()) {
6109 case SCF_ERROR_TYPE_MISMATCH:
6110 if (_add_tmpl_wrong_prop_type_error(errs, pg, pt,
6111 prop) == -1)
6112 goto cleanup;
6113 break;
6115 case SCF_ERROR_INVALID_ARGUMENT:
6117 * tmpl_prop_type shouldn't have handed back
6118 * an invalid property type.
6120 case SCF_ERROR_NOT_SET:
6121 default:
6122 assert(0);
6123 abort();
6128 /* Cardinality */
6129 if (_validate_cardinality(pg, pt, prop, errs) == -1)
6130 goto cleanup;
6132 /* Value constraints */
6134 * Iterate through each value, and confirm it is defined as
6135 * constrained.
6137 if (scf_iter_property_values(iter, prop) != 0) {
6138 assert(scf_error() != SCF_ERROR_NOT_SET &&
6139 scf_error() != SCF_ERROR_HANDLE_MISMATCH);
6140 goto cleanup;
6143 while ((r = scf_iter_next_value(iter, val)) == 1) {
6144 if (_value_in_constraint(pg, prop, pt, val, errs) == -1) {
6145 if (ismember(scf_error(), errors_server)) {
6146 goto cleanup;
6147 } else switch (scf_error()) {
6148 case SCF_ERROR_TEMPLATE_INVALID:
6149 goto cleanup;
6151 case SCF_ERROR_INVALID_ARGUMENT:
6152 default:
6153 assert(0);
6154 abort();
6159 if (r < 0) {
6160 if (ismember(scf_error(), errors_server)) {
6161 goto cleanup;
6162 } else {
6163 assert(0);
6164 abort();
6168 ret = 0;
6170 cleanup:
6171 scf_iter_destroy(iter);
6172 scf_value_destroy(val);
6173 return (ret);
6177 * Returns -1 on failure, sets scf_error() to:
6178 * SCF_ERROR_BACKEND_ACCESS
6179 * SCF_ERROR_CONNECTION_BROKEN
6180 * SCF_ERROR_DELETED
6181 * SCF_ERROR_HANDLE_DESTROYED
6182 * SCF_ERROR_INTERNAL
6183 * SCF_ERROR_NO_MEMORY
6184 * SCF_ERROR_NO_RESOURCES
6185 * SCF_ERROR_NOT_BOUND
6186 * SCF_ERROR_PERMISSION_DENIED
6187 * SCF_ERROR_TEMPLATE_INVALID
6189 static int
6190 _check_pg(scf_pg_tmpl_t *t, scf_propertygroup_t *pg, char *pg_name,
6191 char *type, scf_tmpl_errors_t *errs)
6193 scf_prop_tmpl_t *pt = NULL;
6194 char *pg_type = NULL;
6195 scf_iter_t *iter = NULL;
6196 uint8_t pg_required;
6197 scf_property_t *prop = NULL;
6198 scf_handle_t *h;
6199 int r;
6200 char *prop_name = NULL;
6201 ssize_t nsize = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
6202 int ret = -1;
6204 assert(pg_name != NULL);
6205 assert(t != NULL);
6206 assert(pg != NULL);
6207 assert(type != NULL);
6208 assert(nsize != 0);
6210 if ((h = scf_pg_handle(pg)) == NULL) {
6211 assert(scf_error() == SCF_ERROR_HANDLE_DESTROYED);
6212 return (-1);
6214 if ((pt = scf_tmpl_prop_create(h)) == NULL) {
6215 assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT);
6216 return (-1);
6219 if ((prop = scf_property_create(h)) == NULL) {
6220 assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT);
6221 goto cleanup;
6224 if ((iter = scf_iter_create(h)) == NULL) {
6225 assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT);
6226 goto cleanup;
6228 if ((prop_name = malloc(nsize)) == NULL) {
6229 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
6230 goto cleanup;
6233 if (scf_tmpl_pg_required(t, &pg_required) != 0)
6234 goto cleanup;
6236 if (scf_tmpl_pg_type(t, &pg_type) == -1) {
6237 goto cleanup;
6238 } else if (pg_required != 0 &&
6239 strcmp(SCF_TMPL_WILDCARD, pg_type) == 0) {
6240 /* Type must be specified for required pgs. */
6241 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
6242 goto cleanup;
6245 if (pg_type != NULL) {
6246 if (strcmp(pg_type, type) != 0 &&
6247 strcmp(pg_type, SCF_TMPL_WILDCARD) != 0) {
6248 if (_add_tmpl_wrong_pg_type_error(errs, t, pg) == -1)
6249 goto cleanup;
6254 /* Iterate through properties in the repository and check them. */
6255 if (scf_iter_pg_properties(iter, pg) != 0) {
6256 if (ismember(scf_error(), errors_server)) {
6257 goto cleanup;
6258 } else {
6259 assert(0);
6260 abort();
6264 while ((r = scf_iter_next_property(iter, prop)) == 1) {
6265 if (scf_property_get_name(prop, prop_name, nsize) == -1) {
6266 assert(scf_error() != SCF_ERROR_NOT_SET);
6267 goto cleanup;
6269 if (scf_tmpl_get_by_prop(t, prop_name, pt, 0) != 0) {
6270 if (ismember(scf_error(), errors_server)) {
6271 goto cleanup;
6272 } else switch (scf_error()) {
6273 case SCF_ERROR_NOT_FOUND:
6274 /* No template. Continue. */
6275 continue;
6277 case SCF_ERROR_INVALID_ARGUMENT:
6278 default:
6279 assert(0);
6280 abort();
6284 if (_check_property(pt, pg, prop, errs) != 0)
6285 goto cleanup;
6288 if (r < 0) {
6289 if (ismember(scf_error(), errors_server)) {
6290 goto cleanup;
6291 } else {
6292 assert(0);
6293 abort();
6297 scf_tmpl_prop_reset(pt);
6298 free(prop_name);
6299 prop_name = NULL;
6301 * Confirm required properties are present.
6303 while ((r = scf_tmpl_iter_props(t, pt,
6304 SCF_PROP_TMPL_FLAG_REQUIRED)) == 0) {
6305 scf_type_t prop_type;
6307 if (scf_tmpl_prop_name(pt, &prop_name) == -1)
6308 goto cleanup;
6310 /* required properties cannot have type wildcarded */
6311 if (scf_tmpl_prop_type(pt, &prop_type) == -1) {
6312 if (scf_error() == SCF_ERROR_NOT_FOUND)
6313 (void) scf_set_error(
6314 SCF_ERROR_TEMPLATE_INVALID);
6315 goto cleanup;
6318 if (scf_pg_get_property(pg, prop_name, prop) != 0) {
6319 if (ismember(scf_error(), errors_server)) {
6320 goto cleanup;
6321 } else switch (scf_error()) {
6322 case SCF_ERROR_NOT_FOUND:
6323 if (_add_tmpl_missing_prop_error(errs, t, pg,
6324 pt) == -1)
6325 goto cleanup;
6326 break;
6328 case SCF_ERROR_INVALID_ARGUMENT:
6329 (void) scf_set_error(
6330 SCF_ERROR_TEMPLATE_INVALID);
6331 goto cleanup;
6333 case SCF_ERROR_HANDLE_MISMATCH:
6334 case SCF_ERROR_NOT_SET:
6335 default:
6336 assert(0);
6337 abort();
6340 free(prop_name);
6341 prop_name = NULL;
6343 if (r < 0) {
6344 if (ismember(scf_error(), errors_server)) {
6345 goto cleanup;
6346 } else switch (scf_error()) {
6347 case SCF_ERROR_NOT_FOUND:
6348 break;
6350 case SCF_ERROR_TEMPLATE_INVALID:
6351 goto cleanup;
6353 case SCF_ERROR_INVALID_ARGUMENT:
6354 default:
6355 assert(0);
6356 abort();
6360 ret = 0;
6361 cleanup:
6362 scf_tmpl_prop_destroy(pt);
6363 scf_iter_destroy(iter);
6364 scf_property_destroy(prop);
6365 free(prop_name);
6366 free(pg_type);
6367 return (ret);
6371 * Checks if instance fmri redefines any pgs defined in restarter or global
6372 * Return -1 on failure, sets scf_error() to:
6373 * SCF_ERROR_BACKEND_ACCESS
6374 * SCF_ERROR_CONNECTION_BROKEN
6375 * SCF_ERROR_DELETED
6376 * SCF_ERROR_HANDLE_DESTROYED
6377 * SCF_ERROR_INTERNAL
6378 * SCF_ERROR_INVALID_ARGUMENT
6379 * SCF_ERROR_NO_MEMORY
6380 * SCF_ERROR_NO_RESOURCES
6381 * SCF_ERROR_NOT_BOUND
6382 * SCF_ERROR_NOT_FOUND
6383 * SCF_ERROR_PERMISSION_DENIED
6384 * SCF_ERROR_TEMPLATE_INVALID
6386 static int
6387 _scf_tmpl_check_pg_redef(scf_handle_t *h, const char *fmri,
6388 const char *snapname, scf_tmpl_errors_t *errs)
6390 scf_pg_tmpl_t *t = NULL;
6391 scf_pg_tmpl_t *r = NULL;
6392 char *pg_name = NULL;
6393 char *pg_name_r = NULL;
6394 char *pg_type = NULL;
6395 char *pg_type_r = NULL;
6396 char *target = NULL;
6397 int ret_val = -1;
6398 int ret;
6400 t = scf_tmpl_pg_create(h);
6401 r = scf_tmpl_pg_create(h);
6402 if (t == NULL || r == NULL)
6403 goto cleanup;
6405 while ((ret = scf_tmpl_iter_pgs(t, fmri, snapname, NULL,
6406 SCF_PG_TMPL_FLAG_EXACT)) == 1) {
6407 if (scf_tmpl_pg_name(t, &pg_name) == -1) {
6408 goto cleanup;
6410 if (scf_tmpl_pg_type(t, &pg_type) == -1) {
6411 goto cleanup;
6413 /* look for a redefinition of a global/restarter pg_pattern */
6414 while ((ret = scf_tmpl_iter_pgs(r, fmri, snapname, pg_type,
6415 0)) == 1) {
6416 if (scf_tmpl_pg_name(r, &pg_name_r) == -1) {
6417 goto cleanup;
6418 } else if (strcmp(pg_name_r, SCF_TMPL_WILDCARD) != 0 &&
6419 strcmp(pg_name, SCF_TMPL_WILDCARD) != 0 &&
6420 strcmp(pg_name, pg_name_r) != 0) {
6421 /* not a match */
6422 free(pg_name_r);
6423 pg_name_r = NULL;
6424 continue;
6426 if (scf_tmpl_pg_type(r, &pg_type_r) == -1) {
6427 goto cleanup;
6428 } else if (strcmp(pg_type_r, SCF_TMPL_WILDCARD) != 0 &&
6429 strcmp(pg_type, SCF_TMPL_WILDCARD) != 0 &&
6430 strcmp(pg_type, pg_type_r) != 0) {
6431 /* not a match */
6432 free(pg_name_r);
6433 pg_name_r = NULL;
6434 free(pg_type_r);
6435 pg_type_r = NULL;
6436 continue;
6438 if (scf_tmpl_pg_target(r, &target) == -1) {
6439 target = NULL;
6440 goto cleanup;
6442 if (strcmp(target, SCF_TM_TARGET_ALL) == 0 ||
6443 strcmp(target, SCF_TM_TARGET_DELEGATE) == 0) {
6444 /* found a pg_pattern redefinition */
6445 if (_add_tmpl_pg_redefine_error(errs, t,
6446 r) == -1)
6447 goto cleanup;
6448 free(pg_name_r);
6449 pg_name_r = NULL;
6450 free(pg_type_r);
6451 pg_type_r = NULL;
6452 free(target);
6453 target = NULL;
6454 break;
6456 free(pg_name_r);
6457 pg_name_r = NULL;
6458 free(pg_type_r);
6459 pg_type_r = NULL;
6460 free(target);
6461 target = NULL;
6463 if (ret == -1)
6464 goto cleanup;
6465 scf_tmpl_pg_reset(r);
6467 free(pg_name);
6468 free(pg_type);
6469 pg_name = NULL;
6470 pg_type = NULL;
6472 if (ret == -1)
6473 goto cleanup;
6475 ret_val = 0;
6477 cleanup:
6478 scf_tmpl_pg_destroy(t);
6479 scf_tmpl_pg_destroy(r);
6480 free(pg_name);
6481 free(pg_type);
6482 free(pg_name_r);
6483 free(pg_type_r);
6484 free(target);
6486 if (ret_val == -1) {
6487 if (!ismember(scf_error(), errors_server)) {
6488 switch (scf_error()) {
6489 case SCF_ERROR_TYPE_MISMATCH:
6490 (void) scf_set_error(
6491 SCF_ERROR_TEMPLATE_INVALID);
6492 /*FALLTHROUGH*/
6494 case SCF_ERROR_CONSTRAINT_VIOLATED:
6495 case SCF_ERROR_INVALID_ARGUMENT:
6496 case SCF_ERROR_NOT_FOUND:
6497 case SCF_ERROR_TEMPLATE_INVALID:
6498 break;
6500 case SCF_ERROR_HANDLE_MISMATCH:
6501 case SCF_ERROR_NOT_SET:
6502 default:
6503 assert(0);
6504 abort();
6508 return (ret_val);
6512 * Returns -1 on failure, sets scf_error() to:
6513 * SCF_ERROR_BACKEND_ACCESS
6514 * SCF_ERROR_CONNECTION_BROKEN
6515 * SCF_ERROR_DELETED
6516 * SCF_ERROR_HANDLE_DESTROYED
6517 * SCF_ERROR_INTERNAL
6518 * SCF_ERROR_INVALID_ARGUMENT
6519 * SCF_ERROR_NO_MEMORY
6520 * SCF_ERROR_NO_RESOURCES
6521 * SCF_ERROR_NOT_BOUND
6522 * SCF_ERROR_NOT_FOUND
6523 * SCF_ERROR_PERMISSION_DENIED
6524 * SCF_ERROR_TEMPLATE_INVALID
6527 scf_tmpl_validate_fmri(scf_handle_t *h, const char *fmri, const char *snapshot,
6528 scf_tmpl_errors_t **errs, int flags)
6530 scf_pg_tmpl_t *t = NULL;
6531 scf_iter_t *iter = NULL;
6532 scf_propertygroup_t *pg = NULL;
6533 scf_instance_t *inst = NULL;
6534 scf_snapshot_t *snap = NULL;
6535 char *type = NULL;
6536 char *pg_name = NULL;
6537 ssize_t rsize = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH) + 1;
6538 ssize_t nsize = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
6539 int ret = -1;
6540 int r;
6542 assert(errs != NULL);
6544 if ((*errs = _scf_create_errors(fmri, 1)) == NULL)
6545 return (-1);
6547 if ((pg = scf_pg_create(h)) == NULL ||
6548 (iter = scf_iter_create(h)) == NULL ||
6549 (inst = scf_instance_create(h)) == NULL ||
6550 (t = scf_tmpl_pg_create(h)) == NULL) {
6552 * Sets SCF_ERROR_INVALID_ARGUMENT, SCF_ERROR_NO_MEMORY,
6553 * SCF_ERROR_NO_RESOURCES, SCF_ERROR_INTERNAL or
6554 * SCF_ERROR_HANDLE_DESTROYED.
6556 goto cleanup;
6559 if ((type = malloc(rsize)) == NULL ||
6560 (pg_name = malloc(nsize)) == NULL) {
6561 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
6562 goto cleanup;
6565 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL, NULL,
6566 SCF_DECODE_FMRI_EXACT|SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) {
6567 if (ismember(scf_error(), errors_server)) {
6568 goto cleanup;
6569 } else switch (scf_error()) {
6570 case SCF_ERROR_CONSTRAINT_VIOLATED:
6571 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
6572 /*FALLTHROUGH*/
6574 case SCF_ERROR_INVALID_ARGUMENT:
6575 case SCF_ERROR_NOT_FOUND:
6576 goto cleanup;
6578 case SCF_ERROR_HANDLE_MISMATCH:
6579 case SCF_ERROR_NOT_SET:
6580 default:
6581 assert(0);
6582 abort();
6586 if (snapshot == NULL || strcmp(snapshot, "running") == 0 ||
6587 (flags & SCF_TMPL_VALIDATE_FLAG_CURRENT)) {
6588 if (_get_snapshot(inst, NULL, &snap) == -1)
6589 goto cleanup;
6590 } else {
6591 (void) scf_set_error(SCF_ERROR_NONE);
6592 if (_get_snapshot(inst, snapshot, &snap) == -1) {
6593 goto cleanup;
6594 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
6595 goto cleanup;
6598 if (_scf_tmpl_check_pg_redef(h, fmri, snapshot, *errs) != 0) {
6599 goto cleanup;
6603 * Check that property groups on this instance conform to the template.
6605 if (scf_iter_instance_pgs_composed(iter, inst, snap) != 0) {
6606 if (ismember(scf_error(), errors_server)) {
6607 goto cleanup;
6608 } else {
6609 assert(0);
6610 abort();
6614 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
6615 if (scf_pg_get_name(pg, pg_name, nsize) == -1) {
6616 if (ismember(scf_error(), errors_server)) {
6617 goto cleanup;
6618 } else {
6619 assert(0);
6620 abort();
6624 if (scf_pg_get_type(pg, type, rsize) == -1) {
6625 if (ismember(scf_error(), errors_server)) {
6626 goto cleanup;
6627 } else {
6628 assert(0);
6629 abort();
6633 if (scf_tmpl_get_by_pg_name(fmri, snapshot, pg_name, type, t,
6634 0) != 0) {
6635 if (ismember(scf_error(), errors_server)) {
6636 goto cleanup;
6637 } else switch (scf_error()) {
6638 case SCF_ERROR_NOT_FOUND:
6639 continue;
6641 case SCF_ERROR_INVALID_ARGUMENT:
6642 goto cleanup;
6644 default:
6645 assert(0);
6646 abort();
6650 if (_check_pg(t, pg, pg_name, type, *errs) != 0)
6651 goto cleanup;
6653 if (r < 0) {
6654 if (ismember(scf_error(), errors_server)) {
6655 goto cleanup;
6656 } else {
6657 assert(0);
6658 abort();
6662 scf_tmpl_pg_reset(t);
6665 * Confirm required property groups are present.
6667 while ((r = scf_tmpl_iter_pgs(t, fmri, snapshot, NULL,
6668 SCF_PG_TMPL_FLAG_REQUIRED)) == 1) {
6669 free(pg_name);
6670 free(type);
6672 if (scf_tmpl_pg_name(t, &pg_name) == -1)
6673 goto cleanup;
6674 if (scf_tmpl_pg_type(t, &type) == -1)
6675 goto cleanup;
6677 * required property group templates should not have
6678 * wildcarded name or type
6680 if (strcmp(pg_name, SCF_TMPL_WILDCARD) == 0 ||
6681 strcmp(type, SCF_TMPL_WILDCARD) == 0) {
6682 (void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
6683 goto cleanup;
6686 if (_get_pg(NULL, inst, snap, pg_name, pg) != 0) {
6687 if (ismember(scf_error(), errors_server)) {
6688 goto cleanup;
6689 } else switch (scf_error()) {
6690 case SCF_ERROR_NOT_FOUND:
6691 if (_add_tmpl_missing_pg_error(*errs, t) == -1)
6692 goto cleanup;
6693 continue;
6695 case SCF_ERROR_INVALID_ARGUMENT:
6696 case SCF_ERROR_HANDLE_MISMATCH:
6697 case SCF_ERROR_NOT_SET:
6698 default:
6699 assert(0);
6700 abort();
6704 if (r < 0) {
6705 if (ismember(scf_error(), errors_server)) {
6706 goto cleanup;
6707 } else switch (scf_error()) {
6708 case SCF_ERROR_NOT_FOUND:
6709 break;
6711 case SCF_ERROR_INVALID_ARGUMENT:
6712 goto cleanup;
6714 default:
6715 assert(0);
6716 abort();
6720 ret = 0;
6721 if ((*errs)->tes_num_errs > 0)
6722 ret = 1;
6723 cleanup:
6724 if (ret != 1) {
6725 /* there are no errors to report */
6726 scf_tmpl_errors_destroy(*errs);
6727 *errs = NULL;
6729 scf_tmpl_pg_destroy(t);
6730 free(type);
6731 free(pg_name);
6733 scf_iter_destroy(iter);
6734 scf_pg_destroy(pg);
6735 scf_instance_destroy(inst);
6736 scf_snapshot_destroy(snap);
6738 return (ret);
6741 void
6742 scf_tmpl_errors_destroy(scf_tmpl_errors_t *errs)
6744 int i;
6745 scf_tmpl_error_t *e;
6747 if (errs == NULL)
6748 return;
6750 for (i = 0; i < errs->tes_num_errs; ++i) {
6751 e = errs->tes_errs[i];
6752 if (errs->tes_flag != 0) {
6753 free((char *)e->te_pg_name);
6754 free((char *)e->te_prop_name);
6755 free((char *)e->te_ev1);
6756 free((char *)e->te_ev2);
6757 free((char *)e->te_actual);
6758 free((char *)e->te_tmpl_fmri);
6759 free((char *)e->te_tmpl_pg_name);
6760 free((char *)e->te_tmpl_pg_type);
6761 free((char *)e->te_tmpl_prop_name);
6762 free((char *)e->te_tmpl_prop_type);
6764 free(e);
6766 free((char *)errs->tes_fmri);
6767 free((char *)errs->tes_prefix);
6768 free(errs->tes_errs);
6769 free(errs);
6773 scf_tmpl_error_source_fmri(const scf_tmpl_error_t *err, char **fmri)
6775 assert(err != NULL);
6776 switch (err->te_type) {
6777 case SCF_TERR_MISSING_PG:
6778 case SCF_TERR_WRONG_PG_TYPE:
6779 case SCF_TERR_MISSING_PROP:
6780 case SCF_TERR_WRONG_PROP_TYPE:
6781 case SCF_TERR_CARDINALITY_VIOLATION:
6782 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
6783 case SCF_TERR_RANGE_VIOLATION:
6784 case SCF_TERR_PROP_TYPE_MISMATCH:
6785 case SCF_TERR_VALUE_OUT_OF_RANGE:
6786 case SCF_TERR_INVALID_VALUE:
6787 case SCF_TERR_PG_REDEFINE:
6788 *fmri = (char *)err->te_tmpl_fmri;
6789 return (0);
6790 /*NOTREACHED*/
6791 default:
6792 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
6794 return (-1);
6798 scf_tmpl_error_type(const scf_tmpl_error_t *err, scf_tmpl_error_type_t *type)
6800 assert(err != NULL);
6801 switch (err->te_type) {
6802 case SCF_TERR_MISSING_PG:
6803 case SCF_TERR_WRONG_PG_TYPE:
6804 case SCF_TERR_MISSING_PROP:
6805 case SCF_TERR_WRONG_PROP_TYPE:
6806 case SCF_TERR_CARDINALITY_VIOLATION:
6807 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
6808 case SCF_TERR_RANGE_VIOLATION:
6809 case SCF_TERR_PROP_TYPE_MISMATCH:
6810 case SCF_TERR_VALUE_OUT_OF_RANGE:
6811 case SCF_TERR_INVALID_VALUE:
6812 case SCF_TERR_PG_REDEFINE:
6813 *type = err->te_type;
6814 return (0);
6815 /*NOTREACHED*/
6816 default:
6817 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
6819 return (-1);
6823 scf_tmpl_error_pg_tmpl(const scf_tmpl_error_t *err, char **name, char **type)
6825 assert(err != NULL);
6826 switch (err->te_type) {
6827 case SCF_TERR_MISSING_PG:
6828 case SCF_TERR_WRONG_PG_TYPE:
6829 case SCF_TERR_MISSING_PROP:
6830 case SCF_TERR_WRONG_PROP_TYPE:
6831 case SCF_TERR_CARDINALITY_VIOLATION:
6832 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
6833 case SCF_TERR_RANGE_VIOLATION:
6834 case SCF_TERR_PROP_TYPE_MISMATCH:
6835 case SCF_TERR_VALUE_OUT_OF_RANGE:
6836 case SCF_TERR_INVALID_VALUE:
6837 case SCF_TERR_PG_REDEFINE:
6838 if (err->te_tmpl_pg_name != NULL &&
6839 err->te_tmpl_pg_type != NULL) {
6840 if (name != NULL)
6841 *name = (char *)err->te_tmpl_pg_name;
6842 if (type != NULL)
6843 *type = (char *)err->te_tmpl_pg_type;
6844 return (0);
6846 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
6847 break;
6848 default:
6849 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
6851 return (-1);
6855 scf_tmpl_error_pg(const scf_tmpl_error_t *err, char **name, char **type)
6857 assert(err != NULL);
6858 switch (err->te_type) {
6859 case SCF_TERR_WRONG_PG_TYPE:
6860 if (err->te_pg_name != NULL &&
6861 err->te_actual != NULL) {
6862 if (name != NULL)
6863 *name = (char *)err->te_pg_name;
6864 if (type != NULL)
6865 *type = (char *)err->te_actual;
6866 return (0);
6868 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
6869 break;
6870 case SCF_TERR_WRONG_PROP_TYPE:
6871 case SCF_TERR_CARDINALITY_VIOLATION:
6872 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
6873 case SCF_TERR_RANGE_VIOLATION:
6874 if (err->te_pg_name != NULL &&
6875 err->te_tmpl_pg_type != NULL) {
6876 if (name != NULL)
6877 *name = (char *)err->te_pg_name;
6878 if (type != NULL)
6879 *type = (char *)err->te_tmpl_pg_type;
6880 return (0);
6882 /*FALLTHROUGH*/
6883 case SCF_TERR_MISSING_PROP:
6884 case SCF_TERR_MISSING_PG:
6885 case SCF_TERR_PROP_TYPE_MISMATCH:
6886 case SCF_TERR_VALUE_OUT_OF_RANGE:
6887 case SCF_TERR_INVALID_VALUE:
6888 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
6889 break;
6890 case SCF_TERR_PG_REDEFINE:
6891 if (err->te_ev1 != NULL && err->te_ev2 != NULL) {
6892 if (name != NULL)
6893 *name = (char *)err->te_ev1;
6894 if (type != NULL)
6895 *type = (char *)err->te_ev2;
6896 return (0);
6898 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
6899 break;
6900 default:
6901 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
6903 return (-1);
6907 scf_tmpl_error_prop_tmpl(const scf_tmpl_error_t *err, char **name, char **type)
6909 assert(err != NULL);
6910 switch (err->te_type) {
6911 case SCF_TERR_MISSING_PROP:
6912 case SCF_TERR_WRONG_PROP_TYPE:
6913 case SCF_TERR_CARDINALITY_VIOLATION:
6914 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
6915 case SCF_TERR_RANGE_VIOLATION:
6916 case SCF_TERR_PROP_TYPE_MISMATCH:
6917 case SCF_TERR_VALUE_OUT_OF_RANGE:
6918 case SCF_TERR_INVALID_VALUE:
6919 if (err->te_tmpl_prop_name != NULL &&
6920 err->te_tmpl_prop_type != NULL) {
6921 if (name != NULL)
6922 *name = (char *)err->te_tmpl_prop_name;
6923 if (type != NULL)
6924 *type = (char *)err->te_tmpl_prop_type;
6925 return (0);
6927 /*FALLTHROUGH*/
6928 case SCF_TERR_MISSING_PG:
6929 case SCF_TERR_WRONG_PG_TYPE:
6930 case SCF_TERR_PG_REDEFINE:
6931 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
6932 break;
6933 default:
6934 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
6936 return (-1);
6940 scf_tmpl_error_prop(const scf_tmpl_error_t *err, char **name, char **type)
6942 assert(err != NULL);
6943 switch (err->te_type) {
6944 case SCF_TERR_WRONG_PROP_TYPE:
6945 case SCF_TERR_CARDINALITY_VIOLATION:
6946 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
6947 case SCF_TERR_RANGE_VIOLATION:
6948 if (err->te_prop_name != NULL &&
6949 err->te_tmpl_prop_type != NULL) {
6950 if (name != NULL)
6951 *name = (char *)err->te_prop_name;
6952 if (type != NULL)
6953 *type = (char *)err->te_tmpl_prop_type;
6954 return (0);
6956 /*FALLTHROUGH*/
6957 case SCF_TERR_MISSING_PG:
6958 case SCF_TERR_WRONG_PG_TYPE:
6959 case SCF_TERR_MISSING_PROP:
6960 case SCF_TERR_PROP_TYPE_MISMATCH:
6961 case SCF_TERR_VALUE_OUT_OF_RANGE:
6962 case SCF_TERR_INVALID_VALUE:
6963 case SCF_TERR_PG_REDEFINE:
6964 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
6965 break;
6966 default:
6967 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
6969 return (-1);
6973 scf_tmpl_error_value(const scf_tmpl_error_t *err, char **val)
6975 assert(err != NULL);
6976 switch (err->te_type) {
6977 case SCF_TERR_VALUE_CONSTRAINT_VIOLATED:
6978 case SCF_TERR_RANGE_VIOLATION:
6979 case SCF_TERR_VALUE_OUT_OF_RANGE:
6980 case SCF_TERR_INVALID_VALUE:
6981 if (err->te_actual != NULL) {
6982 if (val != NULL)
6983 *val = (char *)err->te_actual;
6984 return (0);
6986 /*FALLTHROUGH*/
6987 case SCF_TERR_MISSING_PG:
6988 case SCF_TERR_WRONG_PG_TYPE:
6989 case SCF_TERR_MISSING_PROP:
6990 case SCF_TERR_WRONG_PROP_TYPE:
6991 case SCF_TERR_CARDINALITY_VIOLATION:
6992 case SCF_TERR_PROP_TYPE_MISMATCH:
6993 case SCF_TERR_PG_REDEFINE:
6994 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
6995 break;
6996 default:
6997 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
6999 return (-1);
7002 const char *
7003 scf_tmpl_visibility_to_string(uint8_t vis)
7005 if (vis == SCF_TMPL_VISIBILITY_READONLY)
7006 return (SCF_TM_VISIBILITY_READONLY);
7007 else if (vis == SCF_TMPL_VISIBILITY_HIDDEN)
7008 return (SCF_TM_VISIBILITY_HIDDEN);
7009 else if (vis == SCF_TMPL_VISIBILITY_READWRITE)
7010 return (SCF_TM_VISIBILITY_READWRITE);
7011 else
7012 return ("unknown");