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