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