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(