11f6eb021SLiane Praza /*
21f6eb021SLiane Praza  * CDDL HEADER START
31f6eb021SLiane Praza  *
41f6eb021SLiane Praza  * The contents of this file are subject to the terms of the
51f6eb021SLiane Praza  * Common Development and Distribution License (the "License").
61f6eb021SLiane Praza  * You may not use this file except in compliance with the License.
71f6eb021SLiane Praza  *
81f6eb021SLiane Praza  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91f6eb021SLiane Praza  * or http://www.opensolaris.org/os/licensing.
101f6eb021SLiane Praza  * See the License for the specific language governing permissions
111f6eb021SLiane Praza  * and limitations under the License.
121f6eb021SLiane Praza  *
131f6eb021SLiane Praza  * When distributing Covered Code, include this CDDL HEADER in each
141f6eb021SLiane Praza  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151f6eb021SLiane Praza  * If applicable, add the following below this CDDL HEADER, with the
161f6eb021SLiane Praza  * fields enclosed by brackets "[]" replaced with your own identifying
171f6eb021SLiane Praza  * information: Portions Copyright [yyyy] [name of copyright owner]
181f6eb021SLiane Praza  *
191f6eb021SLiane Praza  * CDDL HEADER END
201f6eb021SLiane Praza  */
211f6eb021SLiane Praza /*
22f6e214c7SGavin Maltby  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
23*a58a7fedSMilan Jurik  * Copyright 2012 Milan Jurik. All rights reserved.
241f6eb021SLiane Praza  */
251f6eb021SLiane Praza 
261f6eb021SLiane Praza /*
271f6eb021SLiane Praza  * scf_tmpl.c
281f6eb021SLiane Praza  *
291f6eb021SLiane Praza  * This file implements the bulk of the libscf templates interfaces.
301f6eb021SLiane Praza  * Templates describe metadata about a service or instance in general,
311f6eb021SLiane Praza  * and individual configuration properties on those services and instances.
321f6eb021SLiane Praza  * Human-consumable descriptions can be provided, along with definitions
331f6eb021SLiane Praza  * of valid configuration.  See service_bundle.dtd.1 for XML definitions
341f6eb021SLiane Praza  * of templates, and the svccfg code for information on how those definitions
351f6eb021SLiane Praza  * are translated into the repository.
361f6eb021SLiane Praza  *
371f6eb021SLiane Praza  * The main data structures are scf_pg_tmpl and scf_prop_tmpl.  These
381f6eb021SLiane Praza  * are allocated by the callers through scf_tmpl_[pg|prop]_create(), and
391f6eb021SLiane Praza  * destroyed with scf_tmpl_[pg|prop]_destroy().  They are populated by
401f6eb021SLiane Praza  * scf_tmpl_get_by_pg_name(), scf_tmpl_get_by_pg(), and
411f6eb021SLiane Praza  * scf_tmpl_get_by_prop().  They also store the iterator state for
421f6eb021SLiane Praza  * scf_tmpl_iter_pgs() and scf_tmpl_iter_props().
431f6eb021SLiane Praza  *
441f6eb021SLiane Praza  * These data structures are then consumed by other functions to
451f6eb021SLiane Praza  * gather information about the template (e.g. name, description,
461f6eb021SLiane Praza  * choices, constraints, etc.).
471f6eb021SLiane Praza  *
481f6eb021SLiane Praza  * scf_tmpl_validate_fmri() does instance validation against template
491f6eb021SLiane Praza  * data, and populates a set of template errors which can be explored using
501f6eb021SLiane Praza  * the scf_tmpl_next_error() and the scf_tmpl_error*() suite of functions.
511f6eb021SLiane Praza  *
521f6eb021SLiane Praza  * The main data structures for template errors are scf_tmpl_errors,
531f6eb021SLiane Praza  * defined in this file, and scf_tmpl_error, defined in libscf_priv.h.
541f6eb021SLiane Praza  * scf_tmpl_error is shared with svccfg to offer common printing
551f6eb021SLiane Praza  * of error messages between libscf and svccfg.
561f6eb021SLiane Praza  *
571f6eb021SLiane Praza  * General convenience functions are towards the top of this file,
581f6eb021SLiane Praza  * followed by pg and prop template discovery functions, followed
591f6eb021SLiane Praza  * by functions which gather information about the discovered
601f6eb021SLiane Praza  * template.  Validation and error functions are at the end of this file.
611f6eb021SLiane Praza  */
621f6eb021SLiane Praza 
631f6eb021SLiane Praza #include "lowlevel_impl.h"
641f6eb021SLiane Praza #include "libscf_impl.h"
651f6eb021SLiane Praza #include <assert.h>
661f6eb021SLiane Praza #include <errno.h>
671f6eb021SLiane Praza #include <libintl.h>
681f6eb021SLiane Praza #include <stdlib.h>
691f6eb021SLiane Praza #include <stdio.h>
701f6eb021SLiane Praza #include <strings.h>
711f6eb021SLiane Praza #include <locale.h>
721f6eb021SLiane Praza #include <ctype.h>
731f6eb021SLiane Praza #include <inttypes.h>
741f6eb021SLiane Praza 
751f6eb021SLiane Praza #define	SCF_TMPL_PG_COMMON_NAME_C	"common_name_C"
761f6eb021SLiane Praza 
771f6eb021SLiane Praza #define	SCF__TMPL_ITER_NONE		0
781f6eb021SLiane Praza #define	SCF__TMPL_ITER_INST		1
791f6eb021SLiane Praza #define	SCF__TMPL_ITER_RESTARTER	2
801f6eb021SLiane Praza #define	SCF__TMPL_ITER_GLOBAL		3
811f6eb021SLiane Praza 
821f6eb021SLiane Praza #define	SCF_TMPL_PG_NT		0
831f6eb021SLiane Praza #define	SCF_TMPL_PG_N		1
841f6eb021SLiane Praza #define	SCF_TMPL_PG_T		2
851f6eb021SLiane Praza #define	SCF_TMPL_PG_WILD	3
861f6eb021SLiane Praza 
871f6eb021SLiane Praza struct scf_pg_tmpl {
881f6eb021SLiane Praza 	int pt_populated;
891f6eb021SLiane Praza 	scf_handle_t *pt_h;
901f6eb021SLiane Praza 	scf_propertygroup_t *pt_pg;
911f6eb021SLiane Praza 	scf_service_t *pt_orig_svc;
921f6eb021SLiane Praza 	scf_service_t *pt_svc;
931f6eb021SLiane Praza 	scf_instance_t *pt_orig_inst;
941f6eb021SLiane Praza 	scf_instance_t *pt_inst;
951f6eb021SLiane Praza 	scf_snapshot_t *pt_snap;
961f6eb021SLiane Praza 	int pt_is_iter;
971f6eb021SLiane Praza 	scf_iter_t *pt_iter;
981f6eb021SLiane Praza 	int pt_iter_last;
991f6eb021SLiane Praza };
1001f6eb021SLiane Praza 
1011f6eb021SLiane Praza #define	SCF_WALK_ERROR		-1
1021f6eb021SLiane Praza #define	SCF_WALK_NEXT		0
1031f6eb021SLiane Praza #define	SCF_WALK_DONE		1
1041f6eb021SLiane Praza 
1051f6eb021SLiane Praza struct pg_tmpl_walk {
1061f6eb021SLiane Praza 	const char *pw_snapname;
1071f6eb021SLiane Praza 	const char *pw_pgname;
1081f6eb021SLiane Praza 	const char *pw_pgtype;
1091f6eb021SLiane Praza 	scf_instance_t *pw_inst;
1101f6eb021SLiane Praza 	scf_service_t *pw_svc;
1111f6eb021SLiane Praza 	scf_snapshot_t *pw_snap;
1121f6eb021SLiane Praza 	scf_propertygroup_t *pw_pg;
1131f6eb021SLiane Praza 	const char *pw_target;
1141f6eb021SLiane Praza 	char *pw_tmpl_pgname;
1151f6eb021SLiane Praza };
1161f6eb021SLiane Praza 
1171f6eb021SLiane Praza typedef struct pg_tmpl_walk pg_tmpl_walk_t;
1181f6eb021SLiane Praza 
1191f6eb021SLiane Praza typedef int walk_template_inst_func_t(scf_service_t *_svc,
1201f6eb021SLiane Praza     scf_instance_t *_inst, pg_tmpl_walk_t *p);
1211f6eb021SLiane Praza 
1221f6eb021SLiane Praza struct scf_prop_tmpl {
1231f6eb021SLiane Praza 	int prt_populated;
1241f6eb021SLiane Praza 	scf_handle_t *prt_h;
1251f6eb021SLiane Praza 	scf_pg_tmpl_t *prt_t;
1261f6eb021SLiane Praza 	scf_propertygroup_t *prt_pg;
1271f6eb021SLiane Praza 	char *prt_pg_name;
1281f6eb021SLiane Praza 	scf_iter_t *prt_iter;
1291f6eb021SLiane Praza };
1301f6eb021SLiane Praza 
1311f6eb021SLiane Praza /*
1321f6eb021SLiane Praza  * Common server errors are usually passed back to the caller.  This
1331f6eb021SLiane Praza  * array defines them centrally so that they don't need to be enumerated
1341f6eb021SLiane Praza  * in every libscf call.
1351f6eb021SLiane Praza  */
1361f6eb021SLiane Praza static const scf_error_t errors_server[] = {
1371f6eb021SLiane Praza 	SCF_ERROR_BACKEND_ACCESS,
1381f6eb021SLiane Praza 	SCF_ERROR_CONNECTION_BROKEN,
1391f6eb021SLiane Praza 	SCF_ERROR_DELETED,
1401f6eb021SLiane Praza 	SCF_ERROR_HANDLE_DESTROYED,
1411f6eb021SLiane Praza 	SCF_ERROR_INTERNAL,
1421f6eb021SLiane Praza 	SCF_ERROR_NO_MEMORY,
1431f6eb021SLiane Praza 	SCF_ERROR_NO_RESOURCES,
1441f6eb021SLiane Praza 	SCF_ERROR_NOT_BOUND,
1451f6eb021SLiane Praza 	SCF_ERROR_PERMISSION_DENIED,
1461f6eb021SLiane Praza 	0
1471f6eb021SLiane Praza 	};
1481f6eb021SLiane Praza 
1491f6eb021SLiane Praza /*
1501f6eb021SLiane Praza  * int ismember()
1511f6eb021SLiane Praza  *
1521f6eb021SLiane Praza  * Returns 1 if the supplied error is a member of the error array, 0
1531f6eb021SLiane Praza  * if it is not.
1541f6eb021SLiane Praza  */
155f6e214c7SGavin Maltby int
ismember(const scf_error_t error,const scf_error_t error_array[])156f6e214c7SGavin Maltby ismember(const scf_error_t error, const scf_error_t error_array[])
1571f6eb021SLiane Praza {
1581f6eb021SLiane Praza 	int i;
1591f6eb021SLiane Praza 
1601f6eb021SLiane Praza 	for (i = 0; error_array[i] != 0; ++i) {
1611f6eb021SLiane Praza 		if (error == error_array[i])
1621f6eb021SLiane Praza 			return (1);
1631f6eb021SLiane Praza 	}
1641f6eb021SLiane Praza 
1651f6eb021SLiane Praza 	return (0);
1661f6eb021SLiane Praza }
1671f6eb021SLiane Praza 
1681f6eb021SLiane Praza /*
1691f6eb021SLiane Praza  * char *_scf_tmpl_get_fmri()
1701f6eb021SLiane Praza  *
1711f6eb021SLiane Praza  * Given a pg_tmpl, returns the FMRI of the service or instance that
1721f6eb021SLiane Praza  * template describes.  The allocated string must be freed with free().
1731f6eb021SLiane Praza  *
1741f6eb021SLiane Praza  * On failure, returns NULL and sets scf_error() to _CONNECTION_BROKEN,
1751f6eb021SLiane Praza  * _DELETED, or _NO_MEMORY.
1761f6eb021SLiane Praza  */
1771f6eb021SLiane Praza static char *
_scf_tmpl_get_fmri(const scf_pg_tmpl_t * t)1781f6eb021SLiane Praza _scf_tmpl_get_fmri(const scf_pg_tmpl_t *t)
1791f6eb021SLiane Praza {
1801f6eb021SLiane Praza 	ssize_t sz = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH) + 1;
1811f6eb021SLiane Praza 	int r;
1821f6eb021SLiane Praza 	char *buf = malloc(sz);
1831f6eb021SLiane Praza 
1841f6eb021SLiane Praza 	assert(t->pt_svc != NULL || t->pt_inst != NULL);
1851f6eb021SLiane Praza 	assert(t->pt_svc == NULL || t->pt_inst == NULL);
1861f6eb021SLiane Praza 
1871f6eb021SLiane Praza 	if (buf == NULL) {
1881f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1891f6eb021SLiane Praza 		return (buf);
1901f6eb021SLiane Praza 	}
1911f6eb021SLiane Praza 
1921f6eb021SLiane Praza 	if (t->pt_inst != NULL)
1931f6eb021SLiane Praza 		r = scf_instance_to_fmri(t->pt_inst, buf, sz);
1941f6eb021SLiane Praza 	else
1951f6eb021SLiane Praza 		r = scf_service_to_fmri(t->pt_svc, buf, sz);
1961f6eb021SLiane Praza 
1971f6eb021SLiane Praza 	if (r == -1) {
1981f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
1991f6eb021SLiane Praza 			free(buf);
2001f6eb021SLiane Praza 			buf = NULL;
2011f6eb021SLiane Praza 		} else {
2021f6eb021SLiane Praza 			assert(0);
2031f6eb021SLiane Praza 			abort();
2041f6eb021SLiane Praza 		}
2051f6eb021SLiane Praza 	}
2061f6eb021SLiane Praza 
2071f6eb021SLiane Praza 	return (buf);
2081f6eb021SLiane Praza }
2091f6eb021SLiane Praza 
2101f6eb021SLiane Praza /*
2111f6eb021SLiane Praza  * char *_scf_get_pg_type()
2121f6eb021SLiane Praza  *
2131f6eb021SLiane Praza  * Given a propertygroup, returns an allocated string containing the
2141f6eb021SLiane Praza  * type.  The string must be freed with free().
2151f6eb021SLiane Praza  *
2161f6eb021SLiane Praza  * On failure, returns NULL and sets scf_error() to: _CONNECTION_BROKEN,
2171f6eb021SLiane Praza  * _DELETED, or _NO_MEMORY.
2181f6eb021SLiane Praza  */
2191f6eb021SLiane Praza static char *
_scf_get_pg_type(scf_propertygroup_t * pg)2201f6eb021SLiane Praza _scf_get_pg_type(scf_propertygroup_t *pg)
2211f6eb021SLiane Praza {
2221f6eb021SLiane Praza 	ssize_t sz = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH) + 1;
2231f6eb021SLiane Praza 	char *buf = malloc(sz);
2241f6eb021SLiane Praza 
2251f6eb021SLiane Praza 	if (buf == NULL) {
2261f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
2271f6eb021SLiane Praza 	} else if (scf_pg_get_type(pg, buf, sz) == -1) {
2281f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
2291f6eb021SLiane Praza 			free(buf);
2301f6eb021SLiane Praza 			buf = NULL;
2311f6eb021SLiane Praza 		} else {
2321f6eb021SLiane Praza 			assert(0);
2331f6eb021SLiane Praza 			abort();
2341f6eb021SLiane Praza 		}
2351f6eb021SLiane Praza 	}
2361f6eb021SLiane Praza 
2371f6eb021SLiane Praza 	return (buf);
2381f6eb021SLiane Praza }
2391f6eb021SLiane Praza 
2401f6eb021SLiane Praza /*
2411f6eb021SLiane Praza  * char *_scf_get_prop_name()
2421f6eb021SLiane Praza  *
2431f6eb021SLiane Praza  * Given a property, returns the name in an allocated string.  The string must
2441f6eb021SLiane Praza  * be freed with free().
2451f6eb021SLiane Praza  *
2461f6eb021SLiane Praza  * On error, returns NULL and sets scf_error() to _CONNECTION_BROKEN,
2471f6eb021SLiane Praza  * _DELETED, or _NO_MEMORY.
2481f6eb021SLiane Praza  */
2491f6eb021SLiane Praza static char *
_scf_get_prop_name(scf_property_t * prop)2501f6eb021SLiane Praza _scf_get_prop_name(scf_property_t *prop)
2511f6eb021SLiane Praza {
2521f6eb021SLiane Praza 	ssize_t sz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
2531f6eb021SLiane Praza 	char *buf = malloc(sz);
2541f6eb021SLiane Praza 
2551f6eb021SLiane Praza 	if (buf == NULL) {
2561f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
2571f6eb021SLiane Praza 	} else if (scf_property_get_name(prop, buf, sz) == -1) {
2581f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
2591f6eb021SLiane Praza 			free(buf);
2601f6eb021SLiane Praza 			buf = NULL;
2611f6eb021SLiane Praza 		} else {
2621f6eb021SLiane Praza 			assert(0);
2631f6eb021SLiane Praza 			abort();
2641f6eb021SLiane Praza 		}
2651f6eb021SLiane Praza 	}
2661f6eb021SLiane Praza 
2671f6eb021SLiane Praza 	return (buf);
2681f6eb021SLiane Praza }
2691f6eb021SLiane Praza 
2701f6eb021SLiane Praza /*
2711f6eb021SLiane Praza  * char *_scf_get_prop_type()
2721f6eb021SLiane Praza  *
2731f6eb021SLiane Praza  * Given a property, returns the type in an allocated string.  The string must
2741f6eb021SLiane Praza  * be freed with free().
2751f6eb021SLiane Praza  *
2761f6eb021SLiane Praza  * On error, returns NULL and sets scf_error() to _CONNECTION_BROKEN,
2771f6eb021SLiane Praza  * _DELETED, or _NO_MEMORY.
2781f6eb021SLiane Praza  */
2791f6eb021SLiane Praza static char *
_scf_get_prop_type(scf_property_t * prop)2801f6eb021SLiane Praza _scf_get_prop_type(scf_property_t *prop)
2811f6eb021SLiane Praza {
2821f6eb021SLiane Praza 	scf_type_t type;
2831f6eb021SLiane Praza 	char *ret;
2841f6eb021SLiane Praza 
2851f6eb021SLiane Praza 	if (scf_property_type(prop, &type) == -1) {
2861f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
2871f6eb021SLiane Praza 			return (NULL);
2881f6eb021SLiane Praza 		} else {
2891f6eb021SLiane Praza 			assert(0);
2901f6eb021SLiane Praza 			abort();
2911f6eb021SLiane Praza 		}
2921f6eb021SLiane Praza 	}
2931f6eb021SLiane Praza 
2941f6eb021SLiane Praza 	ret = strdup(scf_type_to_string(type));
2951f6eb021SLiane Praza 	if (ret == NULL)
2961f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
2971f6eb021SLiane Praza 
2981f6eb021SLiane Praza 	return (ret);
2991f6eb021SLiane Praza }
3001f6eb021SLiane Praza 
3011f6eb021SLiane Praza /*
3021f6eb021SLiane Praza  * int _read_single_value_from_pg()
3031f6eb021SLiane Praza  *
3041f6eb021SLiane Praza  * Reads a single value from the pg and property name specified.  On success,
3051f6eb021SLiane Praza  * returns an allocated value that must be freed.
3061f6eb021SLiane Praza  *
3071f6eb021SLiane Praza  * Returns -1 on failure, sets scf_error() to:
3081f6eb021SLiane Praza  *  SCF_ERROR_BACKEND_ACCESS
3091f6eb021SLiane Praza  *  SCF_ERROR_CONNECTION_BROKEN
3101f6eb021SLiane Praza  *  SCF_ERROR_CONSTRAINT_VIOLATED
3111f6eb021SLiane Praza  *    Property has more than one value associated with it.
3121f6eb021SLiane Praza  *  SCF_ERROR_DELETED
3131f6eb021SLiane Praza  *  SCF_ERROR_HANDLE_DESTROYED
3141f6eb021SLiane Praza  *  SCF_ERROR_INTERNAL
3151f6eb021SLiane Praza  *  SCF_ERROR_INVALID_ARGUMENT
3161f6eb021SLiane Praza  *    prop_name not a valid property name.
3171f6eb021SLiane Praza  *  SCF_ERROR_NO_MEMORY
3181f6eb021SLiane Praza  *  SCF_ERROR_NO_RESOURCES
3191f6eb021SLiane Praza  *  SCF_ERROR_NOT_BOUND
3201f6eb021SLiane Praza  *  SCF_ERROR_NOT_FOUND
3211f6eb021SLiane Praza  *    Property doesn't exist or exists and has no value.
3221f6eb021SLiane Praza  *  SCF_ERROR_NOT_SET
3231f6eb021SLiane Praza  *    Property group specified by pg is not set.
3241f6eb021SLiane Praza  *  SCF_ERROR_PERMISSION_DENIED
3251f6eb021SLiane Praza  */
3261f6eb021SLiane Praza static int
_read_single_value_from_pg(scf_propertygroup_t * pg,const char * prop_name,scf_value_t ** val)3271f6eb021SLiane Praza _read_single_value_from_pg(scf_propertygroup_t *pg, const char *prop_name,
3281f6eb021SLiane Praza     scf_value_t **val)
3291f6eb021SLiane Praza {
3301f6eb021SLiane Praza 	scf_handle_t *h;
3311f6eb021SLiane Praza 	scf_property_t *prop;
3321f6eb021SLiane Praza 	int ret = 0;
3331f6eb021SLiane Praza 
3341f6eb021SLiane Praza 	assert(val != NULL);
3351f6eb021SLiane Praza 	if ((h = scf_pg_handle(pg)) == NULL) {
3361f6eb021SLiane Praza 		assert(scf_error() == SCF_ERROR_HANDLE_DESTROYED);
3371f6eb021SLiane Praza 		return (-1);
3381f6eb021SLiane Praza 	}
3391f6eb021SLiane Praza 
3401f6eb021SLiane Praza 	prop = scf_property_create(h);
3411f6eb021SLiane Praza 	*val = scf_value_create(h);
3421f6eb021SLiane Praza 
3431f6eb021SLiane Praza 	if (prop == NULL || *val == NULL) {
3441f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT);
3451f6eb021SLiane Praza 		goto read_single_value_from_pg_fail;
3461f6eb021SLiane Praza 	}
3471f6eb021SLiane Praza 
3481f6eb021SLiane Praza 	if (scf_pg_get_property(pg, prop_name, prop) != 0) {
3491f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_HANDLE_MISMATCH);
3501f6eb021SLiane Praza 		goto read_single_value_from_pg_fail;
3511f6eb021SLiane Praza 	}
3521f6eb021SLiane Praza 
3531f6eb021SLiane Praza 	if (scf_property_get_value(prop, *val) == -1) {
3541f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_NOT_SET);
3551f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_HANDLE_MISMATCH);
3561f6eb021SLiane Praza 		goto read_single_value_from_pg_fail;
3571f6eb021SLiane Praza 	}
3581f6eb021SLiane Praza 
3591f6eb021SLiane Praza 	goto read_single_value_from_pg_done;
3601f6eb021SLiane Praza 
3611f6eb021SLiane Praza read_single_value_from_pg_fail:
3621f6eb021SLiane Praza 	scf_value_destroy(*val);
3631f6eb021SLiane Praza 	*val = NULL;
3641f6eb021SLiane Praza 	ret = -1;
3651f6eb021SLiane Praza 
3661f6eb021SLiane Praza read_single_value_from_pg_done:
3671f6eb021SLiane Praza 	scf_property_destroy(prop);
3681f6eb021SLiane Praza 	return (ret);
3691f6eb021SLiane Praza }
3701f6eb021SLiane Praza 
3711f6eb021SLiane Praza /*
3721f6eb021SLiane Praza  * char *_scf_read_single_astring_from_pg()
3731f6eb021SLiane Praza  *
3741f6eb021SLiane Praza  * Reads an astring from the pg and property name specified.  On success,
3751f6eb021SLiane Praza  * returns an allocated string.  The string must be freed with free().
3761f6eb021SLiane Praza  *
3771f6eb021SLiane Praza  * Returns NULL on failure, sets scf_error() to:
3781f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
3791f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
3801f6eb021SLiane Praza  *   SCF_ERROR_CONSTRAINT_VIOLATED
3811f6eb021SLiane Praza  *     Property has more than one value associated with it.
3821f6eb021SLiane Praza  *   SCF_ERROR_DELETED
3831f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
3841f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
3851f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
3861f6eb021SLiane Praza  *     prop_name not a valid property name.
3871f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
3881f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
3891f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
3901f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
3911f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
3921f6eb021SLiane Praza  *   SCF_ERROR_NOT_SET
3931f6eb021SLiane Praza  *     The property group specified by pg is not set.
3941f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
3951f6eb021SLiane Praza  *   SCF_ERROR_TYPE_MISMATCH
3961f6eb021SLiane Praza  */
3971f6eb021SLiane Praza char *
_scf_read_single_astring_from_pg(scf_propertygroup_t * pg,const char * prop_name)3981f6eb021SLiane Praza _scf_read_single_astring_from_pg(scf_propertygroup_t *pg, const char *prop_name)
3991f6eb021SLiane Praza {
4001f6eb021SLiane Praza 	scf_value_t *val;
4011f6eb021SLiane Praza 	char *ret = NULL;
4021f6eb021SLiane Praza 	ssize_t rsize = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH) + 1;
4031f6eb021SLiane Praza 
4041f6eb021SLiane Praza 	assert(rsize != 0);
4051f6eb021SLiane Praza 	if (_read_single_value_from_pg(pg, prop_name, &val) == -1)
4061f6eb021SLiane Praza 		return (NULL);
4071f6eb021SLiane Praza 
4081f6eb021SLiane Praza 	ret = malloc(rsize);
4091f6eb021SLiane Praza 	if (ret == NULL) {
4101f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
4111f6eb021SLiane Praza 		goto cleanup;
4121f6eb021SLiane Praza 	}
4131f6eb021SLiane Praza 
4141f6eb021SLiane Praza 	if (scf_value_get_astring(val, ret, rsize) < 0) {
4151f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_NOT_SET);
4161f6eb021SLiane Praza 		free(ret);
4171f6eb021SLiane Praza 		ret = NULL;
4181f6eb021SLiane Praza 	}
4191f6eb021SLiane Praza 
4201f6eb021SLiane Praza cleanup:
4211f6eb021SLiane Praza 	scf_value_destroy(val);
4221f6eb021SLiane Praza 	return (ret);
4231f6eb021SLiane Praza }
4241f6eb021SLiane Praza 
4251f6eb021SLiane Praza /*
4261f6eb021SLiane Praza  * char *_scf_read_tmpl_prop_type_as_string()
4271f6eb021SLiane Praza  *
4281f6eb021SLiane Praza  * Reads the property type and returns it as an allocated string.  The string
4291f6eb021SLiane Praza  * must be freed with free().
4301f6eb021SLiane Praza  *
4311f6eb021SLiane Praza  * Returns NULL on failure, sets scf_error() to _BACKEND_ACCESS,
4321f6eb021SLiane Praza  * _CONNECTION_BROKEN, _DELETED, _HANDLE_DESTROYED, _INTERNAL, _NO_MEMORY,
4331f6eb021SLiane Praza  * _NO_RESOURCES, _NOT_BOUND, _PERMISSION_DENIED, or _TEMPLATE_INVALID.
4341f6eb021SLiane Praza  */
4351f6eb021SLiane Praza char *
_scf_read_tmpl_prop_type_as_string(const scf_prop_tmpl_t * pt)4361f6eb021SLiane Praza _scf_read_tmpl_prop_type_as_string(const scf_prop_tmpl_t *pt)
4371f6eb021SLiane Praza {
4381f6eb021SLiane Praza 	char *type;
4391f6eb021SLiane Praza 
4401f6eb021SLiane Praza 	type = _scf_read_single_astring_from_pg(pt->prt_pg,
4411f6eb021SLiane Praza 	    SCF_PROPERTY_TM_TYPE);
4421f6eb021SLiane Praza 	if (type == NULL) {
4431f6eb021SLiane Praza 		if (ismember(scf_error(), errors_server)) {
4441f6eb021SLiane Praza 			return (NULL);
4451f6eb021SLiane Praza 		} else switch (scf_error()) {
4461f6eb021SLiane Praza 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4471f6eb021SLiane Praza 		case SCF_ERROR_NOT_FOUND:
4481f6eb021SLiane Praza 		case SCF_ERROR_TYPE_MISMATCH:
4491f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_TEMPLATE_INVALID);
4501f6eb021SLiane Praza 			return (NULL);
4511f6eb021SLiane Praza 
4521f6eb021SLiane Praza 		case SCF_ERROR_INVALID_ARGUMENT:
4531f6eb021SLiane Praza 		case SCF_ERROR_NOT_SET:
4541f6eb021SLiane Praza 		default:
4551f6eb021SLiane Praza 			assert(0);
4561f6eb021SLiane Praza 			abort();
4571f6eb021SLiane Praza 		}
4581f6eb021SLiane Praza 	}
4591f6eb021SLiane Praza 
4601f6eb021SLiane Praza 	return (type);
4611f6eb021SLiane Praza }
4621f6eb021SLiane Praza 
4631f6eb021SLiane Praza /*
4641f6eb021SLiane Praza  * int _read_single_boolean_from_pg()
4651f6eb021SLiane Praza  *
4661f6eb021SLiane Praza  * Reads a boolean from the pg and property name specified.
4671f6eb021SLiane Praza  *
4681f6eb021SLiane Praza  * Returns -1 on failure, sets scf_error() to:
4691f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
4701f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
4711f6eb021SLiane Praza  *   SCF_ERROR_CONSTRAINT_VIOLATED
4721f6eb021SLiane Praza  *     Property has more than one value associated with it.
4731f6eb021SLiane Praza  *   SCF_ERROR_DELETED
4741f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
4751f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
4761f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
4771f6eb021SLiane Praza  *     prop_name is not a valid property name.
4781f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
4791f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
4801f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
4811f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
4821f6eb021SLiane Praza  *     Property doesn't exist or exists and has no value.
4831f6eb021SLiane Praza  *   SCF_ERROR_NOT_SET
4841f6eb021SLiane Praza  *     The property group specified by pg is not set.
4851f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
4861f6eb021SLiane Praza  *   SCF_ERROR_TYPE_MISMATCH
4871f6eb021SLiane Praza  */
4881f6eb021SLiane Praza static int
_read_single_boolean_from_pg(scf_propertygroup_t * pg,const char * prop_name,uint8_t * bool)4891f6eb021SLiane Praza _read_single_boolean_from_pg(scf_propertygroup_t *pg, const char *prop_name,
4901f6eb021SLiane Praza     uint8_t *bool)
4911f6eb021SLiane Praza {
4921f6eb021SLiane Praza 	scf_value_t *val;
4931f6eb021SLiane Praza 	int ret = 0;
4941f6eb021SLiane Praza 
4951f6eb021SLiane Praza 	if (_read_single_value_from_pg(pg, prop_name, &val) == -1)
4961f6eb021SLiane Praza 		return (-1);
4971f6eb021SLiane Praza 
4981f6eb021SLiane Praza 	if (scf_value_get_boolean(val, bool) < 0) {
4991f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_NOT_SET);
5001f6eb021SLiane Praza 		ret = -1;
5011f6eb021SLiane Praza 	}
5021f6eb021SLiane Praza 
5031f6eb021SLiane Praza 	scf_value_destroy(val);
5041f6eb021SLiane Praza 	return (ret);
5051f6eb021SLiane Praza }
5061f6eb021SLiane Praza 
5071f6eb021SLiane Praza /*
508f6e214c7SGavin Maltby  * static char ** _append_astrings_values()
5091f6eb021SLiane Praza  *
5101f6eb021SLiane Praza  * This function reads the values from the property prop_name in pg and
5111f6eb021SLiane Praza  * appends to an existing scf_values_t *vals.  vals may be empty, but
5121f6eb021SLiane Praza  * must exist.  The function skips over zero-length and duplicate values.
5131f6eb021SLiane Praza  *
5141f6eb021SLiane Praza  * Returns NULL on failure, sets scf_error() to:
5151f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
5161f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
5171f6eb021SLiane Praza  *   SCF_ERROR_DELETED
5181f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
5191f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
5201f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
5211f6eb021SLiane Praza  *     prop_name is not a valid property name.
5221f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
5231f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
5241f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
5251f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
5261f6eb021SLiane Praza  *   SCF_ERROR_NOT_SET
5271f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
5281f6eb021SLiane Praza  *   SCF_ERROR_TYPE_MISMATCH
5291f6eb021SLiane Praza  */
5301f6eb021SLiane Praza static char **
_append_astrings_values(scf_propertygroup_t * pg,const char * prop_name,scf_values_t * vals)5311f6eb021SLiane Praza _append_astrings_values(scf_propertygroup_t *pg, const char *prop_name,
5321f6eb021SLiane Praza     scf_values_t *vals)
5331f6eb021SLiane Praza {
5341f6eb021SLiane Praza 	scf_handle_t *h;
5351f6eb021SLiane Praza 	scf_property_t *prop;
5361f6eb021SLiane Praza 	scf_value_t *val;
5371f6eb021SLiane Praza 	scf_iter_t *iter;
5381f6eb021SLiane Praza 	ssize_t rsize = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH) + 1;
5391f6eb021SLiane Praza 	int err, count, cursz, i;
5401f6eb021SLiane Praza 
5411f6eb021SLiane Praza 	assert(vals != NULL);
5421f6eb021SLiane Praza 	assert(vals->value_type == SCF_TYPE_ASTRING);
5431f6eb021SLiane Praza 	assert(vals->reserved == NULL);
5441f6eb021SLiane Praza 	count = vals->value_count;
5451f6eb021SLiane Praza 	if (count == 0) {
5461f6eb021SLiane Praza 		cursz = 8;
5471f6eb021SLiane Praza 		vals->values.v_astring = calloc(cursz, sizeof (char *));
5481f6eb021SLiane Praza 		if (vals->values.v_astring == NULL) {
5491f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
5501f6eb021SLiane Praza 			return (NULL);
5511f6eb021SLiane Praza 		}
5521f6eb021SLiane Praza 	} else {
5531f6eb021SLiane Praza 		/*
5541f6eb021SLiane Praza 		 * The array may be bigger, but it is irrelevant since
5551f6eb021SLiane Praza 		 * we will always re-allocate a new one.
5561f6eb021SLiane Praza 		 */
5571f6eb021SLiane Praza 		cursz = count;
5581f6eb021SLiane Praza 	}
5591f6eb021SLiane Praza 
5601f6eb021SLiane Praza 	if ((h = scf_pg_handle(pg)) == NULL) {
5611f6eb021SLiane Praza 		assert(scf_error() == SCF_ERROR_HANDLE_DESTROYED);
5621f6eb021SLiane Praza 		return (NULL);
5631f6eb021SLiane Praza 	}
5641f6eb021SLiane Praza 
5651f6eb021SLiane Praza 	prop = scf_property_create(h);
5661f6eb021SLiane Praza 	val = scf_value_create(h);
5671f6eb021SLiane Praza 	iter = scf_iter_create(h);
5681f6eb021SLiane Praza 
5691f6eb021SLiane Praza 	if (prop == NULL || val == NULL || iter == NULL) {
5701f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT);
5711f6eb021SLiane Praza 		goto append_single_astring_from_pg_fail;
5721f6eb021SLiane Praza 	}
5731f6eb021SLiane Praza 
5741f6eb021SLiane Praza 	if (scf_pg_get_property(pg, prop_name, prop) != 0) {
5751f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_HANDLE_MISMATCH);
5761f6eb021SLiane Praza 		goto append_single_astring_from_pg_fail;
5771f6eb021SLiane Praza 	}
5781f6eb021SLiane Praza 
5791f6eb021SLiane Praza 	if (scf_iter_property_values(iter, prop) != 0) {
5801f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_NOT_SET);
5811f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_HANDLE_MISMATCH);
5821f6eb021SLiane Praza 		goto append_single_astring_from_pg_fail;
5831f6eb021SLiane Praza 	}
5841f6eb021SLiane Praza 
5851f6eb021SLiane Praza 	while ((err = scf_iter_next_value(iter, val)) == 1) {
5861f6eb021SLiane Praza 		int flag;
5871f6eb021SLiane Praza 		int r;
5881f6eb021SLiane Praza 
5891f6eb021SLiane Praza 		if (count + 1 >= cursz) {
5901f6eb021SLiane Praza 			void *aux;
5911f6eb021SLiane Praza 
5921f6eb021SLiane Praza 			cursz *= 2;
5931f6eb021SLiane Praza 			if ((aux = calloc(cursz, sizeof (char *))) == NULL) {
5941f6eb021SLiane Praza 				(void) scf_set_error(SCF_ERROR_NO_MEMORY);
5951f6eb021SLiane Praza 				goto append_single_astring_from_pg_fail;
5961f6eb021SLiane Praza 			}
5971f6eb021SLiane Praza 			(void) memcpy(aux, vals->values.v_astring,
5981f6eb021SLiane Praza 			    count * sizeof (char *));
5991f6eb021SLiane Praza 			free(vals->values.v_astring);
6001f6eb021SLiane Praza 			vals->values.v_astring = aux;
6011f6eb021SLiane Praza 		}
6021f6eb021SLiane Praza 
6031f6eb021SLiane Praza 		vals->values.v_astring[count] = malloc(rsize);
6041f6eb021SLiane Praza 		if (vals->values.v_astring[count] == NULL) {
6051f6eb021SLiane Praza 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
6061f6eb021SLiane Praza 			goto append_single_astring_from_pg_fail;
6071f6eb021SLiane Praza 		}
6081f6eb021SLiane Praza 
6091f6eb021SLiane Praza 		if ((r = scf_value_get_astring(val,
6101f6eb021SLiane Praza 		    vals->values.v_astring[count], rsize)) <= 0) {
6111f6eb021SLiane Praza 			/* discard zero length strings */
6121f6eb021SLiane Praza 			if (r == 0) {
6131f6eb021SLiane Praza 				free(vals->values.v_astring[count]);
6141f6eb021SLiane Praza 				continue;
6151f6eb021SLiane Praza 			}
6161f6eb021SLiane Praza 			assert(scf_error() != SCF_ERROR_NOT_SET);
6171f6eb021SLiane Praza 			goto append_single_astring_from_pg_fail;
6181f6eb021SLiane Praza 		}
6191f6eb021SLiane Praza 		for (i = 0, flag = 0; i < count; ++i) {
6201f6eb021SLiane Praza 			/* find  and discard duplicates */
6211f6eb021SLiane Praza 			if (strncmp(vals->values.v_astring[i],
6221f6eb021SLiane Praza 			    vals->values.v_astring[count], rsize) == 0) {
6231f6eb021SLiane Praza 				free(vals->values.v_astring[count]);
6241f6eb021SLiane Praza 				flag = 1;
6251f6eb021SLiane Praza 				break;
6261f6eb021SLiane Praza 			}
6271f6eb021SLiane Praza 		}
6281f6eb021SLiane Praza 		if (flag == 1)
6291f6eb021SLiane Praza 			continue;
6301f6eb021SLiane Praza 
6311f6eb021SLiane Praza 		count++;
6321f6eb021SLiane Praza 	}
6331f6eb021SLiane Praza 
6341f6eb021SLiane Praza 	vals->value_count = count;
6351f6eb021SLiane Praza 
6361f6eb021SLiane Praza 	if (err != 0) {
6371f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_NOT_SET);
6381f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT);
6391f6eb021SLiane Praza 		assert(scf_error() != SCF_ERROR_HANDLE_MISMATCH);
6401f6eb021SLiane Praza 		goto append_single_astring_from_pg_fail;
6411f6eb021SLiane Praza 	} else {
6421f6eb021SLiane Praza 		vals->values_as_strings = vals->values.v_astring;
6431f6eb021SLiane Praza 	}
6441f6eb021SLiane Praza 
6451f6eb021SLiane Praza 	goto append_single_astring_from_pg_done;
6461f6eb021SLiane Praza 
6471f6eb021SLiane Praza append_single_astring_from_pg_fail:
6481f6eb021SLiane Praza 	for (i = 0; i <= count; ++i) {
6491f6eb021SLiane Praza 		if (vals->values.v_astring[i] != NULL)
6501f6eb021SLiane Praza 			free(vals->values.v_astring[i]);
6511f6eb021SLiane Praza 		vals->values.v_astring[i] = NULL;
6521f6eb021SLiane Praza 	}
6531f6eb021SLiane Praza 	free(vals->values.v_astring);
6541f6eb021SLiane Praza 	vals->values.v_astring = NULL;
6551f6eb021SLiane Praza 	vals->value_count = 0;
6561f6eb021SLiane Praza 
6571f6eb021SLiane Praza append_single_astring_from_pg_done:
6581f6eb021SLiane Praza 	scf_iter_destroy(iter);
6591f6eb021SLiane Praza 	scf_property_destroy(prop);
6601f6eb021SLiane Praza 	scf_value_destroy(val);
6611f6eb021SLiane Praza 	return (vals->values.v_astring);
6621f6eb021SLiane Praza }
6631f6eb021SLiane Praza 
6641f6eb021SLiane Praza /*
6651f6eb021SLiane Praza  * Returns NULL on failure, sets scf_error() to:
6661f6eb021SLiane Praza  *   SCF_ERROR_BACKEND_ACCESS
6671f6eb021SLiane Praza  *   SCF_ERROR_CONNECTION_BROKEN
6681f6eb021SLiane Praza  *   SCF_ERROR_DELETED
6691f6eb021SLiane Praza  *   SCF_ERROR_HANDLE_DESTROYED
6701f6eb021SLiane Praza  *   SCF_ERROR_INTERNAL
6711f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
6721f6eb021SLiane Praza  *     prop_name is not a valid property name.
6731f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
6741f6eb021SLiane Praza  *   SCF_ERROR_NO_RESOURCES
6751f6eb021SLiane Praza  *   SCF_ERROR_NOT_BOUND
6761f6eb021SLiane Praza  *   SCF_ERROR_NOT_FOUND
6771f6eb021SLiane Praza  *   SCF_ERROR_NOT_SET
6781f6eb021SLiane Praza  *   SCF_ERROR_PERMISSION_DENIED
6791f6eb021SLiane Praza  *   SCF_ERROR_TYPE_MISMATCH
6801f6eb021SLiane Praza  */
6811f6eb021SLiane Praza static char **
_read_astrings_values(scf_propertygroup_t * pg,const char * prop_name,scf_values_t * vals)6821f6eb021SLiane Praza _read_astrings_values(scf_propertygroup_t *pg, const char *prop_name,
6831f6eb021SLiane Praza     scf_values_t *vals)
6841f6eb021SLiane Praza {
6851f6eb021SLiane Praza 	assert(vals != NULL);
6861f6eb021SLiane Praza 	vals->value_count = 0;
6871f6eb021SLiane Praza 	vals->value_type = SCF_TYPE_ASTRING;
6881f6eb021SLiane Praza 	vals->reserved = NULL;
6891f6eb021SLiane Praza 	return (_append_astrings_values(pg, prop_name, vals));
6901f6eb021SLiane Praza }
6911f6eb021SLiane Praza 
6921f6eb021SLiane Praza void
_scf_sanitize_locale(char * locale)6931f6eb021SLiane Praza _scf_sanitize_locale(char *locale)
6941f6eb021SLiane Praza {
6951f6eb021SLiane Praza 	for (; *locale != '\0'; locale++)
6961f6eb021SLiane Praza 		if (!isalnum(*locale) && *locale != '_')
6971f6eb021SLiane Praza 			*locale = '_';
6981f6eb021SLiane Praza }
6991f6eb021SLiane Praza 
7001f6eb021SLiane Praza /*
7011f6eb021SLiane Praza  * The returned string needs to be freed by the caller
7021f6eb021SLiane Praza  * Returns NULL on failure.  Sets scf_error() to:
7031f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
7041f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
7051f6eb021SLiane Praza  *     Name isn't short enough to add the locale to.
7061f6eb021SLiane Praza  */
7071f6eb021SLiane Praza static char *
_add_locale_to_name(const char * name,const char * locale)7081f6eb021SLiane Praza _add_locale_to_name(const char *name, const char *locale)
7091f6eb021SLiane Praza {
7101f6eb021SLiane Praza 	char *lname = NULL;
7111f6eb021SLiane Praza 	ssize_t lsz;
7121f6eb021SLiane Praza 	char *loc;
7131f6eb021SLiane Praza 
7141f6eb021SLiane Praza 	if (locale == NULL)
7151f6eb021SLiane Praza 		locale = setlocale(LC_MESSAGES, NULL);
7161f6eb021SLiane Praza 	loc = strdup(locale);
7171f6eb021SLiane Praza 	if (loc == NULL) {
7181f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
7191f6eb021SLiane Praza 		return (NULL);
7201f6eb021SLiane Praza 	} else {
7211f6eb021SLiane Praza 		_scf_sanitize_locale(loc);
7221f6eb021SLiane Praza 	}
7231f6eb021SLiane Praza 
7241f6eb021SLiane Praza 	lsz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
7251f6eb021SLiane Praza 	lname = malloc(lsz);
7261f6eb021SLiane Praza 	if (lname == NULL) {
7271f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
7281f6eb021SLiane Praza 		goto cleanup;
7291f6eb021SLiane Praza 	}
7301f6eb021SLiane Praza 
7311f6eb021SLiane Praza 	(void) strlcpy(lname, name, lsz);
7321f6eb021SLiane Praza 	if (strlcat(lname, loc, lsz) >= lsz) {
7331f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
7341f6eb021SLiane Praza 		free(lname);
7351f6eb021SLiane Praza 		lname = NULL;
7361f6eb021SLiane Praza 	}
7371f6eb021SLiane Praza cleanup:
7381f6eb021SLiane Praza 	free(loc);
7391f6eb021SLiane Praza 
7401f6eb021SLiane Praza 	return (lname);
7411f6eb021SLiane Praza }
7421f6eb021SLiane Praza 
7431f6eb021SLiane Praza /*
7441f6eb021SLiane Praza  * char *_tmpl_pg_name(pg, type, use_type)
7451f6eb021SLiane Praza  *
7461f6eb021SLiane Praza  * pg and type can both be NULL.  Returns the name of the most specific
7471f6eb021SLiane Praza  * template property group name based on the inputs.
7481f6eb021SLiane Praza  * If use_type is set and pg is not NULL, a property group name for a
7491f6eb021SLiane Praza  * property group template that has type defined is returned, even if no
7501f6eb021SLiane Praza  * type is provided.
7511f6eb021SLiane Praza  *
7521f6eb021SLiane Praza  * Returns NULL on failure and sets scf_error() to:
7531f6eb021SLiane Praza  *   SCF_ERROR_INVALID_ARGUMENT
7541f6eb021SLiane Praza  *     can't combine the arguments and get a reasonable length name
7551f6eb021SLiane Praza  *   SCF_ERROR_NO_MEMORY
7561f6eb021SLiane Praza  *
7571f6eb021SLiane Praza  */
7581f6eb021SLiane Praza static char *
_tmpl_pg_name(const char * pg,const char * type,int use_type)7591f6eb021SLiane Praza _tmpl_pg_name(const char *pg, const char *type, int use_type)
7601f6eb021SLiane Praza {
7611f6eb021SLiane Praza 	char *name;
7621f6eb021SLiane Praza 	ssize_t limit, size = 0;
7631f6eb021SLiane Praza 
7641f6eb021SLiane Praza 	limit = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
7651f6eb021SLiane Praza 	name = malloc(limit);
7661f6eb021SLiane Praza 	if (name == NULL) {
7671f6eb021SLiane Praza 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
7681f6eb021SLiane Praza 		return (NULL);
7691f6eb021SLiane Praza 	}
7701f6eb021SLiane Praza 
7711f6eb021SLiane Praza 	if (pg == NULL && type == NULL) {
7721f6eb021SLiane Praza 		if (strlcpy(name, SCF_PG_TM_PG_PATTERN_PREFIX, limit) >=
7731f6eb021SLiane Praza 		    limit) {
7741f6eb021SLiane Praza 			assert(0);
7751f6eb021SLiane Praza 			abort();
7761f6eb021SLiane Praza 		}
7771f6eb021SLiane Praza 		return (name);
7781f6eb021SLiane Praza 	} else if (pg != NULL && type != NULL) {
7791f6eb021SLiane Praza 		size = snprintf(