1d71dbb73Sjbeck /* 2d71dbb73Sjbeck * CDDL HEADER START 3d71dbb73Sjbeck * 4d71dbb73Sjbeck * The contents of this file are subject to the terms of the 5d71dbb73Sjbeck * Common Development and Distribution License (the "License"). 6d71dbb73Sjbeck * You may not use this file except in compliance with the License. 7d71dbb73Sjbeck * 8d71dbb73Sjbeck * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9d71dbb73Sjbeck * or http://www.opensolaris.org/os/licensing. 10d71dbb73Sjbeck * See the License for the specific language governing permissions 11d71dbb73Sjbeck * and limitations under the License. 12d71dbb73Sjbeck * 13d71dbb73Sjbeck * When distributing Covered Code, include this CDDL HEADER in each 14d71dbb73Sjbeck * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15d71dbb73Sjbeck * If applicable, add the following below this CDDL HEADER, with the 16d71dbb73Sjbeck * fields enclosed by brackets "[]" replaced with your own identifying 17d71dbb73Sjbeck * information: Portions Copyright [yyyy] [name of copyright owner] 18d71dbb73Sjbeck * 19d71dbb73Sjbeck * CDDL HEADER END 20d71dbb73Sjbeck */ 21d71dbb73Sjbeck 22d71dbb73Sjbeck /* 23*f6da83d4SAnurag S. Maskey * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 24d71dbb73Sjbeck */ 25d71dbb73Sjbeck 26d71dbb73Sjbeck /* 276ba597c5SAnurag S. Maskey * util.c contains a set of miscellaneous utility functions which, 286ba597c5SAnurag S. Maskey * among other things: 29d71dbb73Sjbeck * - start a child process 30d71dbb73Sjbeck * - look up the zone name 316ba597c5SAnurag S. Maskey * - look up/set SMF properties 326ba597c5SAnurag S. Maskey * - drop/escalate privs 33d71dbb73Sjbeck */ 34d71dbb73Sjbeck 356ba597c5SAnurag S. Maskey #include <assert.h> 366ba597c5SAnurag S. Maskey #include <errno.h> 376ba597c5SAnurag S. Maskey #include <libdllink.h> 386ba597c5SAnurag S. Maskey #include <limits.h> 396ba597c5SAnurag S. Maskey #include <libscf.h> 406ba597c5SAnurag S. Maskey #include <net/if.h> 416ba597c5SAnurag S. Maskey #include <pthread.h> 426ba597c5SAnurag S. Maskey #include <pwd.h> 436ba597c5SAnurag S. Maskey #include <spawn.h> 44d71dbb73Sjbeck #include <stdarg.h> 45d71dbb73Sjbeck #include <stdio.h> 46d71dbb73Sjbeck #include <stdlib.h> 47d71dbb73Sjbeck #include <string.h> 486ba597c5SAnurag S. Maskey #include <strings.h> 49d71dbb73Sjbeck #include <stropts.h> 50d71dbb73Sjbeck #include <sys/socket.h> 516ba597c5SAnurag S. Maskey #include <sys/sockio.h> 526ba597c5SAnurag S. Maskey #include <sys/types.h> 536ba597c5SAnurag S. Maskey #include <unistd.h> 54d71dbb73Sjbeck #include <wait.h> 55d71dbb73Sjbeck #include <zone.h> 56d71dbb73Sjbeck 576ba597c5SAnurag S. Maskey #include "util.h" 586ba597c5SAnurag S. Maskey #include "llp.h" 59d71dbb73Sjbeck 60d71dbb73Sjbeck extern char **environ; 616ba597c5SAnurag S. Maskey extern sigset_t original_sigmask; 62d71dbb73Sjbeck 63d71dbb73Sjbeck /* 646ba597c5SAnurag S. Maskey * A holder for all the resources needed to get a property value 656ba597c5SAnurag S. Maskey * using libscf. 66d71dbb73Sjbeck */ 676ba597c5SAnurag S. Maskey typedef struct scf_resources { 686ba597c5SAnurag S. Maskey scf_handle_t *sr_handle; 696ba597c5SAnurag S. Maskey scf_instance_t *sr_inst; 706ba597c5SAnurag S. Maskey scf_snapshot_t *sr_snap; 716ba597c5SAnurag S. Maskey scf_propertygroup_t *sr_pg; 726ba597c5SAnurag S. Maskey scf_property_t *sr_prop; 736ba597c5SAnurag S. Maskey scf_value_t *sr_val; 746ba597c5SAnurag S. Maskey scf_transaction_t *sr_tx; 756ba597c5SAnurag S. Maskey scf_transaction_entry_t *sr_ent; 766ba597c5SAnurag S. Maskey } scf_resources_t; 77d71dbb73Sjbeck 786ba597c5SAnurag S. Maskey static pthread_mutex_t uid_mutex = PTHREAD_MUTEX_INITIALIZER; 796ba597c5SAnurag S. Maskey static uid_t uid; 806ba597c5SAnurag S. Maskey static int uid_cnt; 81d71dbb73Sjbeck 82b00044a2SJames Carlson void 8338f140aaSMichael Hunter nwamd_escalate(void) { 8438f140aaSMichael Hunter priv_set_t *priv_set; 8538f140aaSMichael Hunter priv_set = priv_str_to_set("zone", ",", NULL); 8638f140aaSMichael Hunter 8738f140aaSMichael Hunter if (priv_set == NULL) 8838f140aaSMichael Hunter pfail("creating privilege set: %s", strerror(errno)); 8938f140aaSMichael Hunter 906ba597c5SAnurag S. Maskey (void) pthread_mutex_lock(&uid_mutex); 916ba597c5SAnurag S. Maskey if (uid == 0) 926ba597c5SAnurag S. Maskey uid = getuid(); 936ba597c5SAnurag S. Maskey if (uid_cnt++ == 0) { 9438f140aaSMichael Hunter if (setppriv(PRIV_SET, PRIV_EFFECTIVE, priv_set) == -1) { 9538f140aaSMichael Hunter priv_freeset(priv_set); 9638f140aaSMichael Hunter pfail("setppriv effective: %s", strerror(errno)); 9738f140aaSMichael Hunter } 98b00044a2SJames Carlson } 996ba597c5SAnurag S. Maskey (void) pthread_mutex_unlock(&uid_mutex); 10038f140aaSMichael Hunter 10138f140aaSMichael Hunter priv_freeset(priv_set); 1026ba597c5SAnurag S. Maskey } 1036ba597c5SAnurag S. Maskey 1046ba597c5SAnurag S. Maskey void 10538f140aaSMichael Hunter nwamd_deescalate(void) { 1066ba597c5SAnurag S. Maskey (void) pthread_mutex_lock(&uid_mutex); 1073773ed2dSAnurag S. Maskey 1086ba597c5SAnurag S. Maskey assert(uid_cnt > 0); 1096ba597c5SAnurag S. Maskey if (--uid_cnt == 0) { 1103773ed2dSAnurag S. Maskey priv_set_t *priv_set, *allpriv_set; 1113773ed2dSAnurag S. Maskey 11238f140aaSMichael Hunter /* build up our minimal set of privs. */ 11338f140aaSMichael Hunter priv_set = priv_str_to_set("basic", ",", NULL); 11438f140aaSMichael Hunter allpriv_set = priv_str_to_set("zone", ",", NULL); 11538f140aaSMichael Hunter if (priv_set == NULL || allpriv_set == NULL) 11638f140aaSMichael Hunter pfail("converting privilege sets: %s", strerror(errno)); 11738f140aaSMichael Hunter 11838f140aaSMichael Hunter (void) priv_addset(priv_set, PRIV_FILE_CHOWN_SELF); 11938f140aaSMichael Hunter (void) priv_addset(priv_set, PRIV_FILE_DAC_READ); 12038f140aaSMichael Hunter (void) priv_addset(priv_set, PRIV_FILE_DAC_WRITE); 12138f140aaSMichael Hunter (void) priv_addset(priv_set, PRIV_NET_RAWACCESS); 12238f140aaSMichael Hunter (void) priv_addset(priv_set, PRIV_NET_PRIVADDR); 12338f140aaSMichael Hunter (void) priv_addset(priv_set, PRIV_PROC_AUDIT); 12438f140aaSMichael Hunter (void) priv_addset(priv_set, PRIV_PROC_OWNER); 12538f140aaSMichael Hunter (void) priv_addset(priv_set, PRIV_PROC_SETID); 12638f140aaSMichael Hunter (void) priv_addset(priv_set, PRIV_SYS_CONFIG); 12738f140aaSMichael Hunter (void) priv_addset(priv_set, PRIV_SYS_IP_CONFIG); 12838f140aaSMichael Hunter (void) priv_addset(priv_set, PRIV_SYS_IPC_CONFIG); 12938f140aaSMichael Hunter (void) priv_addset(priv_set, PRIV_SYS_MOUNT); 13038f140aaSMichael Hunter (void) priv_addset(priv_set, PRIV_SYS_NET_CONFIG); 13138f140aaSMichael Hunter (void) priv_addset(priv_set, PRIV_SYS_RES_CONFIG); 13238f140aaSMichael Hunter (void) priv_addset(priv_set, PRIV_SYS_RESOURCE); 13338f140aaSMichael Hunter 13438f140aaSMichael Hunter /* 13538f140aaSMichael Hunter * Since our zone might not have all these privs, 13638f140aaSMichael Hunter * just ask for those that are available. 13738f140aaSMichael Hunter */ 13838f140aaSMichael Hunter priv_intersect(allpriv_set, priv_set); 13938f140aaSMichael Hunter 14038f140aaSMichael Hunter if (setppriv(PRIV_SET, PRIV_INHERITABLE, priv_set) == -1) { 14138f140aaSMichael Hunter priv_freeset(allpriv_set); 14238f140aaSMichael Hunter priv_freeset(priv_set); 14338f140aaSMichael Hunter pfail("setppriv inheritable: %s", strerror(errno)); 14438f140aaSMichael Hunter } 14538f140aaSMichael Hunter /* 14638f140aaSMichael Hunter * Need to ensure permitted set contains all privs so we can 14738f140aaSMichael Hunter * escalate later. 14838f140aaSMichael Hunter */ 14938f140aaSMichael Hunter if (setppriv(PRIV_SET, PRIV_PERMITTED, allpriv_set) == -1) { 15038f140aaSMichael Hunter priv_freeset(allpriv_set); 15138f140aaSMichael Hunter priv_freeset(priv_set); 15238f140aaSMichael Hunter pfail("setppriv permitted: %s", strerror(errno)); 15338f140aaSMichael Hunter } 15438f140aaSMichael Hunter /* 15538f140aaSMichael Hunter * We need to find a smaller set of privs that are important to 15638f140aaSMichael Hunter * us. Otherwise we really are not gaining much by doing this. 15738f140aaSMichael Hunter */ 15838f140aaSMichael Hunter if (setppriv(PRIV_SET, PRIV_EFFECTIVE, priv_set) == -1) { 15938f140aaSMichael Hunter priv_freeset(allpriv_set); 16038f140aaSMichael Hunter priv_freeset(priv_set); 16138f140aaSMichael Hunter pfail("setppriv effective: %s", strerror(errno)); 16238f140aaSMichael Hunter } 16338f140aaSMichael Hunter 16438f140aaSMichael Hunter priv_freeset(priv_set); 16538f140aaSMichael Hunter priv_freeset(allpriv_set); 166b00044a2SJames Carlson } 1673773ed2dSAnurag S. Maskey (void) pthread_mutex_unlock(&uid_mutex); 1683773ed2dSAnurag S. Maskey } 169b00044a2SJames Carlson 170d71dbb73Sjbeck /* 171d71dbb73Sjbeck * 172d71dbb73Sjbeck * This starts a child process determined by command. If command contains a 173d71dbb73Sjbeck * slash then it is assumed to be a full path; otherwise the path is searched 174d71dbb73Sjbeck * for an executable file with the name command. Command is also used as 175d71dbb73Sjbeck * argv[0] of the new process. The rest of the arguments of the function 176d71dbb73Sjbeck * up to the first NULL make up pointers to arguments of the new process. 177d71dbb73Sjbeck * 178d71dbb73Sjbeck * This function returns child exit status on success and -1 on failure. 179d71dbb73Sjbeck * 180d71dbb73Sjbeck * NOTE: original_sigmask must be set before this function is called. 181d71dbb73Sjbeck */ 182d71dbb73Sjbeck int 1836ba597c5SAnurag S. Maskey nwamd_start_childv(const char *command, char const * const *argv) 184d71dbb73Sjbeck { 185d71dbb73Sjbeck posix_spawnattr_t attr; 186d71dbb73Sjbeck sigset_t fullset; 187d71dbb73Sjbeck int i, rc, status, n; 188d71dbb73Sjbeck pid_t pid; 189d71dbb73Sjbeck char vbuf[1024]; 190d71dbb73Sjbeck 191d71dbb73Sjbeck vbuf[0] = 0; 192d71dbb73Sjbeck n = sizeof (vbuf); 193d71dbb73Sjbeck for (i = 1; argv[i] != NULL && n > 2; i++) { 194d71dbb73Sjbeck n -= strlcat(vbuf, " ", n); 195d71dbb73Sjbeck n -= strlcat(vbuf, argv[i], n); 196d71dbb73Sjbeck } 197d71dbb73Sjbeck if (argv[i] != NULL || n < 0) 1986ba597c5SAnurag S. Maskey nlog(LOG_ERR, "nwamd_start_childv can't log full arg vector"); 199d71dbb73Sjbeck 200d71dbb73Sjbeck if ((rc = posix_spawnattr_init(&attr)) != 0) { 2016ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "posix_spawnattr_init %d %s\n", 2026ba597c5SAnurag S. Maskey rc, strerror(rc)); 203d71dbb73Sjbeck return (-1); 204d71dbb73Sjbeck } 205d71dbb73Sjbeck (void) sigfillset(&fullset); 206d71dbb73Sjbeck if ((rc = posix_spawnattr_setsigdefault(&attr, &fullset)) != 0) { 2076ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "setsigdefault %d %s\n", rc, strerror(rc)); 208d71dbb73Sjbeck return (-1); 209d71dbb73Sjbeck } 210d71dbb73Sjbeck if ((rc = posix_spawnattr_setsigmask(&attr, &original_sigmask)) != 0) { 2116ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "setsigmask %d %s\n", rc, strerror(rc)); 212d71dbb73Sjbeck return (-1); 213d71dbb73Sjbeck } 214d71dbb73Sjbeck if ((rc = posix_spawnattr_setflags(&attr, 215d71dbb73Sjbeck POSIX_SPAWN_SETSIGDEF|POSIX_SPAWN_SETSIGMASK)) != 0) { 2166ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "setflags %d %s\n", rc, strerror(rc)); 217d71dbb73Sjbeck return (-1); 218d71dbb73Sjbeck } 219d71dbb73Sjbeck 220d71dbb73Sjbeck if ((rc = posix_spawnp(&pid, command, NULL, &attr, (char * const *)argv, 221d71dbb73Sjbeck environ)) > 0) { 2226ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "posix_spawnp failed errno %d", rc); 223d71dbb73Sjbeck return (-1); 224d71dbb73Sjbeck } 225d71dbb73Sjbeck 226d71dbb73Sjbeck if ((rc = posix_spawnattr_destroy(&attr)) != 0) { 2276ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "posix_spawn_attr_destroy %d %s\n", 2286ba597c5SAnurag S. Maskey rc, strerror(rc)); 229d71dbb73Sjbeck return (-1); 230d71dbb73Sjbeck } 231d71dbb73Sjbeck 232d71dbb73Sjbeck (void) waitpid(pid, &status, 0); 233d71dbb73Sjbeck if (WIFSIGNALED(status) || WIFSTOPPED(status)) { 234d71dbb73Sjbeck i = WIFSIGNALED(status) ? WTERMSIG(status) : WSTOPSIG(status); 2356ba597c5SAnurag S. Maskey nlog(LOG_ERR, "'%s%s' %s with signal %d (%s)", command, vbuf, 236d71dbb73Sjbeck (WIFSIGNALED(status) ? "terminated" : "stopped"), i, 237d71dbb73Sjbeck strsignal(i)); 238d71dbb73Sjbeck return (-2); 239d71dbb73Sjbeck } else { 2406ba597c5SAnurag S. Maskey nlog(LOG_INFO, "'%s%s' completed normally: %d", command, vbuf, 241d71dbb73Sjbeck WEXITSTATUS(status)); 242d71dbb73Sjbeck return (WEXITSTATUS(status)); 243d71dbb73Sjbeck } 244d71dbb73Sjbeck } 245d71dbb73Sjbeck 2466ba597c5SAnurag S. Maskey /* 2476ba597c5SAnurag S. Maskey * For global zone, check if the link is used by a non-global 2486ba597c5SAnurag S. Maskey * zone, note that the non-global zones doesn't need this check, 2496ba597c5SAnurag S. Maskey * because zoneadm has taken care of this when the zone boots. 2506ba597c5SAnurag S. Maskey * In the global zone, we ignore events for local-zone-owned links 2516ba597c5SAnurag S. Maskey * since these are taken care of by the local zone's network 2526ba597c5SAnurag S. Maskey * configuration services. 2536ba597c5SAnurag S. Maskey */ 2546ba597c5SAnurag S. Maskey boolean_t 2556ba597c5SAnurag S. Maskey nwamd_link_belongs_to_this_zone(const char *linkname) 256d71dbb73Sjbeck { 2576ba597c5SAnurag S. Maskey zoneid_t zoneid; 2586ba597c5SAnurag S. Maskey char zonename[ZONENAME_MAX]; 2596ba597c5SAnurag S. Maskey int ret; 260d71dbb73Sjbeck 2616ba597c5SAnurag S. Maskey zoneid = getzoneid(); 2626ba597c5SAnurag S. Maskey if (zoneid == GLOBAL_ZONEID) { 2636ba597c5SAnurag S. Maskey datalink_id_t linkid; 2646ba597c5SAnurag S. Maskey dladm_status_t status; 2656ba597c5SAnurag S. Maskey char errstr[DLADM_STRSIZE]; 266d71dbb73Sjbeck 2676ba597c5SAnurag S. Maskey if ((status = dladm_name2info(dld_handle, linkname, &linkid, 2686ba597c5SAnurag S. Maskey NULL, NULL, NULL)) != DLADM_STATUS_OK) { 2696ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "nwamd_link_belongs_to_this_zone: " 2706ba597c5SAnurag S. Maskey "could not get linkid for %s: %s", 2716ba597c5SAnurag S. Maskey linkname, dladm_status2str(status, errstr)); 2726ba597c5SAnurag S. Maskey return (B_FALSE); 2736ba597c5SAnurag S. Maskey } 2746ba597c5SAnurag S. Maskey zoneid = ALL_ZONES; 2756ba597c5SAnurag S. Maskey ret = zone_check_datalink(&zoneid, linkid); 2766ba597c5SAnurag S. Maskey if (ret == 0) { 2776ba597c5SAnurag S. Maskey (void) getzonenamebyid(zoneid, zonename, ZONENAME_MAX); 2786ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "nwamd_link_belongs_to_this_zone: " 2796ba597c5SAnurag S. Maskey "%s is used by non-global zone: %s", 2806ba597c5SAnurag S. Maskey linkname, zonename); 2816ba597c5SAnurag S. Maskey return (B_FALSE); 282d71dbb73Sjbeck } 283d71dbb73Sjbeck } 2846ba597c5SAnurag S. Maskey return (B_TRUE); 285d71dbb73Sjbeck } 286d71dbb73Sjbeck 2876ba597c5SAnurag S. Maskey /* 2886ba597c5SAnurag S. Maskey * Inputs: 2896ba597c5SAnurag S. Maskey * res is a pointer to the scf_resources_t to be released. 2906ba597c5SAnurag S. Maskey */ 2916ba597c5SAnurag S. Maskey static void 2926ba597c5SAnurag S. Maskey release_scf_resources(scf_resources_t *res) 2936ba597c5SAnurag S. Maskey { 2946ba597c5SAnurag S. Maskey scf_entry_destroy(res->sr_ent); 2956ba597c5SAnurag S. Maskey scf_transaction_destroy(res->sr_tx); 2966ba597c5SAnurag S. Maskey scf_value_destroy(res->sr_val); 2976ba597c5SAnurag S. Maskey scf_property_destroy(res->sr_prop); 2986ba597c5SAnurag S. Maskey scf_pg_destroy(res->sr_pg); 2996ba597c5SAnurag S. Maskey scf_snapshot_destroy(res->sr_snap); 3006ba597c5SAnurag S. Maskey scf_instance_destroy(res->sr_inst); 3016ba597c5SAnurag S. Maskey (void) scf_handle_unbind(res->sr_handle); 3026ba597c5SAnurag S. Maskey scf_handle_destroy(res->sr_handle); 3036ba597c5SAnurag S. Maskey } 3046ba597c5SAnurag S. Maskey 3056ba597c5SAnurag S. Maskey /* 3066ba597c5SAnurag S. Maskey * Inputs: 3076ba597c5SAnurag S. Maskey * fmri is the instance to look up 3086ba597c5SAnurag S. Maskey * Outputs: 3096ba597c5SAnurag S. Maskey * res is a pointer to an scf_resources_t. This is an internal 3106ba597c5SAnurag S. Maskey * structure that holds all the handles needed to get a specific 3116ba597c5SAnurag S. Maskey * property from the running snapshot; on a successful return it 3126ba597c5SAnurag S. Maskey * contains the scf_value_t that should be passed to the desired 3136ba597c5SAnurag S. Maskey * scf_value_get_foo() function, and must be freed after use by 3146ba597c5SAnurag S. Maskey * calling release_scf_resources(). On a failure return, any 3156ba597c5SAnurag S. Maskey * resources that may have been assigned to res are released, so 3166ba597c5SAnurag S. Maskey * the caller does not need to do any cleanup in the failure case. 3176ba597c5SAnurag S. Maskey * Returns: 3186ba597c5SAnurag S. Maskey * 0 on success 3196ba597c5SAnurag S. Maskey * -1 on failure 3206ba597c5SAnurag S. Maskey */ 3216ba597c5SAnurag S. Maskey 3226ba597c5SAnurag S. Maskey static int 3236ba597c5SAnurag S. Maskey create_scf_resources(const char *fmri, scf_resources_t *res) 3246ba597c5SAnurag S. Maskey { 3256ba597c5SAnurag S. Maskey res->sr_tx = NULL; 3266ba597c5SAnurag S. Maskey res->sr_ent = NULL; 3276ba597c5SAnurag S. Maskey res->sr_inst = NULL; 3286ba597c5SAnurag S. Maskey res->sr_snap = NULL; 3296ba597c5SAnurag S. Maskey res->sr_pg = NULL; 3306ba597c5SAnurag S. Maskey res->sr_prop = NULL; 3316ba597c5SAnurag S. Maskey res->sr_val = NULL; 3326ba597c5SAnurag S. Maskey 3336ba597c5SAnurag S. Maskey if ((res->sr_handle = scf_handle_create(SCF_VERSION)) == NULL) { 3346ba597c5SAnurag S. Maskey return (-1); 3356ba597c5SAnurag S. Maskey } 3366ba597c5SAnurag S. Maskey 3376ba597c5SAnurag S. Maskey if (scf_handle_bind(res->sr_handle) != 0) { 3386ba597c5SAnurag S. Maskey scf_handle_destroy(res->sr_handle); 3396ba597c5SAnurag S. Maskey return (-1); 3406ba597c5SAnurag S. Maskey } 3416ba597c5SAnurag S. Maskey if ((res->sr_inst = scf_instance_create(res->sr_handle)) == NULL) { 3426ba597c5SAnurag S. Maskey goto failure; 3436ba597c5SAnurag S. Maskey } 3446ba597c5SAnurag S. Maskey if (scf_handle_decode_fmri(res->sr_handle, fmri, NULL, NULL, 3456ba597c5SAnurag S. Maskey res->sr_inst, NULL, NULL, SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) { 3466ba597c5SAnurag S. Maskey goto failure; 3476ba597c5SAnurag S. Maskey } 3486ba597c5SAnurag S. Maskey if ((res->sr_snap = scf_snapshot_create(res->sr_handle)) == NULL) { 3496ba597c5SAnurag S. Maskey goto failure; 3506ba597c5SAnurag S. Maskey } 3516ba597c5SAnurag S. Maskey if (scf_instance_get_snapshot(res->sr_inst, "running", 3526ba597c5SAnurag S. Maskey res->sr_snap) != 0) { 3536ba597c5SAnurag S. Maskey goto failure; 3546ba597c5SAnurag S. Maskey } 3556ba597c5SAnurag S. Maskey if ((res->sr_pg = scf_pg_create(res->sr_handle)) == NULL) { 3566ba597c5SAnurag S. Maskey goto failure; 3576ba597c5SAnurag S. Maskey } 3586ba597c5SAnurag S. Maskey if ((res->sr_prop = scf_property_create(res->sr_handle)) == NULL) { 3596ba597c5SAnurag S. Maskey goto failure; 3606ba597c5SAnurag S. Maskey } 3616ba597c5SAnurag S. Maskey if ((res->sr_val = scf_value_create(res->sr_handle)) == NULL) { 3626ba597c5SAnurag S. Maskey goto failure; 3636ba597c5SAnurag S. Maskey } 3646ba597c5SAnurag S. Maskey if ((res->sr_tx = scf_transaction_create(res->sr_handle)) == NULL) { 3656ba597c5SAnurag S. Maskey goto failure; 3666ba597c5SAnurag S. Maskey } 3676ba597c5SAnurag S. Maskey if ((res->sr_ent = scf_entry_create(res->sr_handle)) == NULL) { 3686ba597c5SAnurag S. Maskey goto failure; 3696ba597c5SAnurag S. Maskey } 3706ba597c5SAnurag S. Maskey return (0); 3716ba597c5SAnurag S. Maskey 3726ba597c5SAnurag S. Maskey failure: 3736ba597c5SAnurag S. Maskey nlog(LOG_ERR, "create_scf_resources failed: %s", 3746ba597c5SAnurag S. Maskey scf_strerror(scf_error())); 3756ba597c5SAnurag S. Maskey release_scf_resources(res); 3766ba597c5SAnurag S. Maskey return (-1); 3776ba597c5SAnurag S. Maskey } 3786ba597c5SAnurag S. Maskey 3796ba597c5SAnurag S. Maskey /* 3806ba597c5SAnurag S. Maskey * Inputs: 3816ba597c5SAnurag S. Maskey * fmri is the instance to look up 3826ba597c5SAnurag S. Maskey * pg is the property group to look up 3836ba597c5SAnurag S. Maskey * prop is the property within that group to look up 3846ba597c5SAnurag S. Maskey * running specifies if running snapshot is to be used 3856ba597c5SAnurag S. Maskey * Outputs: 3866ba597c5SAnurag S. Maskey * res is a pointer to an scf_resources_t. This is an internal 3876ba597c5SAnurag S. Maskey * structure that holds all the handles needed to get a specific 3886ba597c5SAnurag S. Maskey * property from the running snapshot; on a successful return it 3896ba597c5SAnurag S. Maskey * contains the scf_value_t that should be passed to the desired 3906ba597c5SAnurag S. Maskey * scf_value_get_foo() function, and must be freed after use by 3916ba597c5SAnurag S. Maskey * calling release_scf_resources(). On a failure return, any 3926ba597c5SAnurag S. Maskey * resources that may have been assigned to res are released, so 3936ba597c5SAnurag S. Maskey * the caller does not need to do any cleanup in the failure case. 3946ba597c5SAnurag S. Maskey * Returns: 3956ba597c5SAnurag S. Maskey * 0 on success 3966ba597c5SAnurag S. Maskey * -1 on failure 3976ba597c5SAnurag S. Maskey */ 3986ba597c5SAnurag S. Maskey static int 3996ba597c5SAnurag S. Maskey get_property_value(const char *fmri, const char *pg, const char *prop, 4006ba597c5SAnurag S. Maskey boolean_t running, scf_resources_t *res) 4016ba597c5SAnurag S. Maskey { 4026ba597c5SAnurag S. Maskey if (create_scf_resources(fmri, res) != 0) 4036ba597c5SAnurag S. Maskey return (-1); 4046ba597c5SAnurag S. Maskey 4056ba597c5SAnurag S. Maskey if (scf_instance_get_pg_composed(res->sr_inst, 4066ba597c5SAnurag S. Maskey running ? res->sr_snap : NULL, pg, res->sr_pg) != 0) { 4076ba597c5SAnurag S. Maskey goto failure; 4086ba597c5SAnurag S. Maskey } 4096ba597c5SAnurag S. Maskey if (scf_pg_get_property(res->sr_pg, prop, res->sr_prop) != 0) { 4106ba597c5SAnurag S. Maskey goto failure; 4116ba597c5SAnurag S. Maskey } 4126ba597c5SAnurag S. Maskey if (scf_property_get_value(res->sr_prop, res->sr_val) != 0) { 4136ba597c5SAnurag S. Maskey goto failure; 4146ba597c5SAnurag S. Maskey } 4156ba597c5SAnurag S. Maskey return (0); 4166ba597c5SAnurag S. Maskey 4176ba597c5SAnurag S. Maskey failure: 4186ba597c5SAnurag S. Maskey release_scf_resources(res); 4196ba597c5SAnurag S. Maskey return (-1); 4206ba597c5SAnurag S. Maskey } 4216ba597c5SAnurag S. Maskey 4226ba597c5SAnurag S. Maskey /* 4236ba597c5SAnurag S. Maskey * Inputs: 4246ba597c5SAnurag S. Maskey * lfmri is the instance fmri to look up 4256ba597c5SAnurag S. Maskey * lpg is the property group to look up 4266ba597c5SAnurag S. Maskey * lprop is the property within that group to look up 4276ba597c5SAnurag S. Maskey * Outputs: 4286ba597c5SAnurag S. Maskey * answer is a pointer to the property value 4296ba597c5SAnurag S. Maskey * Returns: 4306ba597c5SAnurag S. Maskey * 0 on success 4316ba597c5SAnurag S. Maskey * -1 on failure 4326ba597c5SAnurag S. Maskey * If successful, the property value is retured in *answer. 4336ba597c5SAnurag S. Maskey * Otherwise, *answer is undefined, and it is up to the caller to decide 4346ba597c5SAnurag S. Maskey * how to handle that case. 4356ba597c5SAnurag S. Maskey */ 4366ba597c5SAnurag S. Maskey int 4376ba597c5SAnurag S. Maskey nwamd_lookup_boolean_property(const char *lfmri, const char *lpg, 4386ba597c5SAnurag S. Maskey const char *lprop, boolean_t *answer) 4396ba597c5SAnurag S. Maskey { 4406ba597c5SAnurag S. Maskey int result = -1; 4416ba597c5SAnurag S. Maskey scf_resources_t res; 4426ba597c5SAnurag S. Maskey uint8_t prop_val; 4436ba597c5SAnurag S. Maskey 4446ba597c5SAnurag S. Maskey if (get_property_value(lfmri, lpg, lprop, B_TRUE, &res) != 0) { 4456ba597c5SAnurag S. Maskey 4466ba597c5SAnurag S. Maskey /* 4476ba597c5SAnurag S. Maskey * an error was already logged by get_property_value, 4486ba597c5SAnurag S. Maskey * and it released any resources assigned to res before 4496ba597c5SAnurag S. Maskey * returning. 4506ba597c5SAnurag S. Maskey */ 4516ba597c5SAnurag S. Maskey return (result); 4526ba597c5SAnurag S. Maskey } 4536ba597c5SAnurag S. Maskey if (scf_value_get_boolean(res.sr_val, &prop_val) != 0) { 4546ba597c5SAnurag S. Maskey goto cleanup; 4556ba597c5SAnurag S. Maskey } 4566ba597c5SAnurag S. Maskey *answer = (boolean_t)prop_val; 4576ba597c5SAnurag S. Maskey result = 0; 4586ba597c5SAnurag S. Maskey cleanup: 4596ba597c5SAnurag S. Maskey release_scf_resources(&res); 4606ba597c5SAnurag S. Maskey return (result); 4616ba597c5SAnurag S. Maskey } 4626ba597c5SAnurag S. Maskey 4636ba597c5SAnurag S. Maskey /* 4646ba597c5SAnurag S. Maskey * Inputs: 4656ba597c5SAnurag S. Maskey * lfmri is the instance fmri to look up 4666ba597c5SAnurag S. Maskey * lpg is the property group to look up 4676ba597c5SAnurag S. Maskey * lprop is the property within that group to look up 4686ba597c5SAnurag S. Maskey * buf is the place to put the answer 4696ba597c5SAnurag S. Maskey * bufsz is the size of buf 4706ba597c5SAnurag S. Maskey * Outputs: 4716ba597c5SAnurag S. Maskey * 4726ba597c5SAnurag S. Maskey * Returns: 4736ba597c5SAnurag S. Maskey * 0 on success 4746ba597c5SAnurag S. Maskey * -1 on failure 4756ba597c5SAnurag S. Maskey * If successful, the property value is retured in buf. 4766ba597c5SAnurag S. Maskey * Otherwise, buf is undefined, and it is up to the caller to decide 4776ba597c5SAnurag S. Maskey * how to handle that case. 4786ba597c5SAnurag S. Maskey */ 4796ba597c5SAnurag S. Maskey int 4806ba597c5SAnurag S. Maskey nwamd_lookup_string_property(const char *lfmri, const char *lpg, 4816ba597c5SAnurag S. Maskey const char *lprop, char *buf, size_t bufsz) 4826ba597c5SAnurag S. Maskey { 4836ba597c5SAnurag S. Maskey int result = -1; 4846ba597c5SAnurag S. Maskey scf_resources_t res; 4856ba597c5SAnurag S. Maskey 4866ba597c5SAnurag S. Maskey if (get_property_value(lfmri, lpg, lprop, B_TRUE, &res) != 0) { 4876ba597c5SAnurag S. Maskey /* 4886ba597c5SAnurag S. Maskey * The above function fails when trying to get a 4896ba597c5SAnurag S. Maskey * non-persistent property group from the running snapshot. 4906ba597c5SAnurag S. Maskey * Try going for the non-running snapshot. 4916ba597c5SAnurag S. Maskey */ 4926ba597c5SAnurag S. Maskey if (get_property_value(lfmri, lpg, lprop, B_FALSE, &res) != 0) { 4936ba597c5SAnurag S. Maskey /* 4946ba597c5SAnurag S. Maskey * an error was already logged by get_property_value, 4956ba597c5SAnurag S. Maskey * and it released any resources assigned to res before 4966ba597c5SAnurag S. Maskey * returning. 4976ba597c5SAnurag S. Maskey */ 4986ba597c5SAnurag S. Maskey return (result); 4996ba597c5SAnurag S. Maskey } 5006ba597c5SAnurag S. Maskey } 5016ba597c5SAnurag S. Maskey if (scf_value_get_astring(res.sr_val, buf, bufsz) == 0) 5026ba597c5SAnurag S. Maskey goto cleanup; 5036ba597c5SAnurag S. Maskey 5046ba597c5SAnurag S. Maskey result = 0; 5056ba597c5SAnurag S. Maskey cleanup: 5066ba597c5SAnurag S. Maskey release_scf_resources(&res); 5076ba597c5SAnurag S. Maskey return (result); 5086ba597c5SAnurag S. Maskey } 5096ba597c5SAnurag S. Maskey 5106ba597c5SAnurag S. Maskey /* 5116ba597c5SAnurag S. Maskey * Inputs: 5126ba597c5SAnurag S. Maskey * lfmri is the instance fmri to look up 5136ba597c5SAnurag S. Maskey * lpg is the property group to look up 5146ba597c5SAnurag S. Maskey * lprop is the property within that group to look up 5156ba597c5SAnurag S. Maskey * Outputs: 5166ba597c5SAnurag S. Maskey * answer is a pointer to the property value 5176ba597c5SAnurag S. Maskey * Returns: 5186ba597c5SAnurag S. Maskey * 0 on success 5196ba597c5SAnurag S. Maskey * -1 on failure 5206ba597c5SAnurag S. Maskey * If successful, the property value is retured in *answer. 5216ba597c5SAnurag S. Maskey * Otherwise, *answer is undefined, and it is up to the caller to decide 5226ba597c5SAnurag S. Maskey * how to handle that case. 5236ba597c5SAnurag S. Maskey */ 5246ba597c5SAnurag S. Maskey int 5256ba597c5SAnurag S. Maskey nwamd_lookup_count_property(const char *lfmri, const char *lpg, 5266ba597c5SAnurag S. Maskey const char *lprop, uint64_t *answer) 5276ba597c5SAnurag S. Maskey { 5286ba597c5SAnurag S. Maskey int result = -1; 5296ba597c5SAnurag S. Maskey scf_resources_t res; 5306ba597c5SAnurag S. Maskey 5316ba597c5SAnurag S. Maskey if (get_property_value(lfmri, lpg, lprop, B_TRUE, &res) != 0) { 5326ba597c5SAnurag S. Maskey 5336ba597c5SAnurag S. Maskey /* 5346ba597c5SAnurag S. Maskey * an error was already logged by get_property_value, 5356ba597c5SAnurag S. Maskey * and it released any resources assigned to res before 5366ba597c5SAnurag S. Maskey * returning. 5376ba597c5SAnurag S. Maskey */ 5386ba597c5SAnurag S. Maskey return (result); 5396ba597c5SAnurag S. Maskey } 5406ba597c5SAnurag S. Maskey if (scf_value_get_count(res.sr_val, answer) != 0) { 5416ba597c5SAnurag S. Maskey goto cleanup; 5426ba597c5SAnurag S. Maskey } 5436ba597c5SAnurag S. Maskey result = 0; 5446ba597c5SAnurag S. Maskey cleanup: 5456ba597c5SAnurag S. Maskey release_scf_resources(&res); 5466ba597c5SAnurag S. Maskey return (result); 5476ba597c5SAnurag S. Maskey } 5486ba597c5SAnurag S. Maskey 5496ba597c5SAnurag S. Maskey static int 5506ba597c5SAnurag S. Maskey set_property_value(scf_resources_t *res, const char *propname, 5516ba597c5SAnurag S. Maskey scf_type_t proptype) 5526ba597c5SAnurag S. Maskey { 5536ba597c5SAnurag S. Maskey int result = -1; 5546ba597c5SAnurag S. Maskey boolean_t new; 5556ba597c5SAnurag S. Maskey 5566ba597c5SAnurag S. Maskey retry: 5576ba597c5SAnurag S. Maskey new = (scf_pg_get_property(res->sr_pg, propname, res->sr_prop) != 0); 5586ba597c5SAnurag S. Maskey 5596ba597c5SAnurag S. Maskey if (scf_transaction_start(res->sr_tx, res->sr_pg) == -1) { 5606ba597c5SAnurag S. Maskey goto failure; 5616ba597c5SAnurag S. Maskey } 5626ba597c5SAnurag S. Maskey if (new) { 5636ba597c5SAnurag S. Maskey if (scf_transaction_property_new(res->sr_tx, res->sr_ent, 5646ba597c5SAnurag S. Maskey propname, proptype) == -1) { 5656ba597c5SAnurag S. Maskey goto failure; 5666ba597c5SAnurag S. Maskey } 5676ba597c5SAnurag S. Maskey } else { 5686ba597c5SAnurag S. Maskey if (scf_transaction_property_change(res->sr_tx, res->sr_ent, 5696ba597c5SAnurag S. Maskey propname, proptype) == -1) { 5706ba597c5SAnurag S. Maskey goto failure; 5716ba597c5SAnurag S. Maskey } 5726ba597c5SAnurag S. Maskey } 5736ba597c5SAnurag S. Maskey 5746ba597c5SAnurag S. Maskey if (scf_entry_add_value(res->sr_ent, res->sr_val) != 0) { 5756ba597c5SAnurag S. Maskey goto failure; 5766ba597c5SAnurag S. Maskey } 5776ba597c5SAnurag S. Maskey 5786ba597c5SAnurag S. Maskey result = scf_transaction_commit(res->sr_tx); 5796ba597c5SAnurag S. Maskey if (result == 0) { 5806ba597c5SAnurag S. Maskey scf_transaction_reset(res->sr_tx); 5816ba597c5SAnurag S. Maskey if (scf_pg_update(res->sr_pg) == -1) { 5826ba597c5SAnurag S. Maskey goto failure; 5836ba597c5SAnurag S. Maskey } 5846ba597c5SAnurag S. Maskey nlog(LOG_INFO, "set_property_value: transaction commit failed " 5856ba597c5SAnurag S. Maskey "for %s; retrying", propname); 5866ba597c5SAnurag S. Maskey goto retry; 5876ba597c5SAnurag S. Maskey } 5886ba597c5SAnurag S. Maskey if (result == -1) 5896ba597c5SAnurag S. Maskey goto failure; 5906ba597c5SAnurag S. Maskey return (0); 5916ba597c5SAnurag S. Maskey 5926ba597c5SAnurag S. Maskey failure: 5936ba597c5SAnurag S. Maskey return (-1); 5946ba597c5SAnurag S. Maskey } 5956ba597c5SAnurag S. Maskey 5966ba597c5SAnurag S. Maskey int 5976ba597c5SAnurag S. Maskey nwamd_set_count_property(const char *fmri, const char *pg, const char *prop, 5986ba597c5SAnurag S. Maskey uint64_t count) 5996ba597c5SAnurag S. Maskey { 6006ba597c5SAnurag S. Maskey scf_resources_t res; 6016ba597c5SAnurag S. Maskey 6026ba597c5SAnurag S. Maskey if (create_scf_resources(fmri, &res) != 0) 6036ba597c5SAnurag S. Maskey return (-1); 6046ba597c5SAnurag S. Maskey 6056ba597c5SAnurag S. Maskey if (scf_instance_add_pg(res.sr_inst, pg, SCF_GROUP_APPLICATION, 6066ba597c5SAnurag S. Maskey SCF_PG_FLAG_NONPERSISTENT, res.sr_pg) != 0) { 6076ba597c5SAnurag S. Maskey if (scf_error() != SCF_ERROR_EXISTS) 6086ba597c5SAnurag S. Maskey goto failure; 6096ba597c5SAnurag S. Maskey if (scf_instance_get_pg_composed(res.sr_inst, NULL, pg, 6106ba597c5SAnurag S. Maskey res.sr_pg) != 0) 6116ba597c5SAnurag S. Maskey goto failure; 6126ba597c5SAnurag S. Maskey } 6136ba597c5SAnurag S. Maskey 6146ba597c5SAnurag S. Maskey scf_value_set_count(res.sr_val, (uint64_t)count); 6156ba597c5SAnurag S. Maskey 6166ba597c5SAnurag S. Maskey if (set_property_value(&res, prop, SCF_TYPE_COUNT) != 0) 6176ba597c5SAnurag S. Maskey goto failure; 6186ba597c5SAnurag S. Maskey 6196ba597c5SAnurag S. Maskey release_scf_resources(&res); 6206ba597c5SAnurag S. Maskey return (0); 6216ba597c5SAnurag S. Maskey 6226ba597c5SAnurag S. Maskey failure: 6236ba597c5SAnurag S. Maskey nlog(LOG_INFO, "nwamd_set_count_property: scf failure %s while " 6246ba597c5SAnurag S. Maskey "setting %s", scf_strerror(scf_error()), prop); 6256ba597c5SAnurag S. Maskey release_scf_resources(&res); 6266ba597c5SAnurag S. Maskey return (-1); 6276ba597c5SAnurag S. Maskey } 6286ba597c5SAnurag S. Maskey 6296ba597c5SAnurag S. Maskey int 6306ba597c5SAnurag S. Maskey nwamd_set_string_property(const char *fmri, const char *pg, const char *prop, 6316ba597c5SAnurag S. Maskey const char *str) 6326ba597c5SAnurag S. Maskey { 6336ba597c5SAnurag S. Maskey scf_resources_t res; 6346ba597c5SAnurag S. Maskey 6356ba597c5SAnurag S. Maskey if (create_scf_resources(fmri, &res) != 0) 6366ba597c5SAnurag S. Maskey return (-1); 6376ba597c5SAnurag S. Maskey 6386ba597c5SAnurag S. Maskey if (scf_instance_add_pg(res.sr_inst, pg, SCF_GROUP_APPLICATION, 6396ba597c5SAnurag S. Maskey SCF_PG_FLAG_NONPERSISTENT, res.sr_pg) != 0) { 6406ba597c5SAnurag S. Maskey if (scf_error() != SCF_ERROR_EXISTS) 6416ba597c5SAnurag S. Maskey goto failure; 6426ba597c5SAnurag S. Maskey if (scf_instance_get_pg_composed(res.sr_inst, NULL, pg, 6436ba597c5SAnurag S. Maskey res.sr_pg) != 0) 6446ba597c5SAnurag S. Maskey goto failure; 6456ba597c5SAnurag S. Maskey } 6466ba597c5SAnurag S. Maskey 6476ba597c5SAnurag S. Maskey if (scf_value_set_astring(res.sr_val, str) != 0) 6486ba597c5SAnurag S. Maskey goto failure; 6496ba597c5SAnurag S. Maskey 6506ba597c5SAnurag S. Maskey if (set_property_value(&res, prop, SCF_TYPE_ASTRING) != 0) 6516ba597c5SAnurag S. Maskey goto failure; 6526ba597c5SAnurag S. Maskey 6536ba597c5SAnurag S. Maskey release_scf_resources(&res); 6546ba597c5SAnurag S. Maskey return (0); 6556ba597c5SAnurag S. Maskey 6566ba597c5SAnurag S. Maskey failure: 6576ba597c5SAnurag S. Maskey nlog(LOG_INFO, "nwamd_set_string_property: scf failure %s while " 6586ba597c5SAnurag S. Maskey "setting %s", scf_strerror(scf_error()), prop); 6596ba597c5SAnurag S. Maskey release_scf_resources(&res); 6606ba597c5SAnurag S. Maskey return (-1); 6616ba597c5SAnurag S. Maskey } 6626ba597c5SAnurag S. Maskey 6636ba597c5SAnurag S. Maskey /* 6646ba597c5SAnurag S. Maskey * Deletes property prop from property group pg in SMF instance fmri. 6656ba597c5SAnurag S. Maskey * Returns 0 on success, -1 on failure. 6666ba597c5SAnurag S. Maskey */ 6676ba597c5SAnurag S. Maskey int 6686ba597c5SAnurag S. Maskey nwamd_delete_scf_property(const char *fmri, const char *pg, const char *prop) 6696ba597c5SAnurag S. Maskey { 6706ba597c5SAnurag S. Maskey scf_resources_t res; 6716ba597c5SAnurag S. Maskey int result = -1; 6726ba597c5SAnurag S. Maskey 6736ba597c5SAnurag S. Maskey if (create_scf_resources(fmri, &res) != 0) 6746ba597c5SAnurag S. Maskey return (-1); 6756ba597c5SAnurag S. Maskey 6766ba597c5SAnurag S. Maskey if (scf_instance_add_pg(res.sr_inst, pg, SCF_GROUP_APPLICATION, 6776ba597c5SAnurag S. Maskey SCF_PG_FLAG_NONPERSISTENT, res.sr_pg) != 0) { 6786ba597c5SAnurag S. Maskey if (scf_error() != SCF_ERROR_EXISTS) 6796ba597c5SAnurag S. Maskey goto failure; 6806ba597c5SAnurag S. Maskey if (scf_instance_get_pg_composed(res.sr_inst, NULL, pg, 6816ba597c5SAnurag S. Maskey res.sr_pg) != 0) 6826ba597c5SAnurag S. Maskey goto failure; 6836ba597c5SAnurag S. Maskey } 6846ba597c5SAnurag S. Maskey 6856ba597c5SAnurag S. Maskey if (scf_pg_get_property(res.sr_pg, prop, res.sr_prop) != 0) 6866ba597c5SAnurag S. Maskey goto failure; 6876ba597c5SAnurag S. Maskey retry: 6886ba597c5SAnurag S. Maskey if (scf_transaction_start(res.sr_tx, res.sr_pg) == -1) 6896ba597c5SAnurag S. Maskey goto failure; 6906ba597c5SAnurag S. Maskey 6916ba597c5SAnurag S. Maskey if (scf_transaction_property_delete(res.sr_tx, res.sr_ent, prop) == -1) 6926ba597c5SAnurag S. Maskey goto failure; 6936ba597c5SAnurag S. Maskey 6946ba597c5SAnurag S. Maskey result = scf_transaction_commit(res.sr_tx); 6956ba597c5SAnurag S. Maskey if (result == 0) { 6966ba597c5SAnurag S. Maskey scf_transaction_reset(res.sr_tx); 6976ba597c5SAnurag S. Maskey if (scf_pg_update(res.sr_pg) == -1) 6986ba597c5SAnurag S. Maskey goto failure; 6996ba597c5SAnurag S. Maskey goto retry; 7006ba597c5SAnurag S. Maskey } 7016ba597c5SAnurag S. Maskey if (result == -1) 7026ba597c5SAnurag S. Maskey goto failure; 7036ba597c5SAnurag S. Maskey 7046ba597c5SAnurag S. Maskey release_scf_resources(&res); 7056ba597c5SAnurag S. Maskey return (0); 7066ba597c5SAnurag S. Maskey failure: 7076ba597c5SAnurag S. Maskey release_scf_resources(&res); 7086ba597c5SAnurag S. Maskey return (-1); 709d71dbb73Sjbeck } 710