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*6ba597c5SAnurag S. Maskey * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24d71dbb73Sjbeck * Use is subject to license terms. 25d71dbb73Sjbeck */ 26d71dbb73Sjbeck 27d71dbb73Sjbeck /* 28*6ba597c5SAnurag S. Maskey * util.c contains a set of miscellaneous utility functions which, 29*6ba597c5SAnurag S. Maskey * among other things: 30d71dbb73Sjbeck * - start a child process 31d71dbb73Sjbeck * - look up the zone name 32*6ba597c5SAnurag S. Maskey * - look up/set SMF properties 33*6ba597c5SAnurag S. Maskey * - drop/escalate privs 34d71dbb73Sjbeck */ 35d71dbb73Sjbeck 36*6ba597c5SAnurag S. Maskey #include <assert.h> 37*6ba597c5SAnurag S. Maskey #include <errno.h> 38*6ba597c5SAnurag S. Maskey #include <inetcfg.h> 39*6ba597c5SAnurag S. Maskey #include <libdllink.h> 40*6ba597c5SAnurag S. Maskey #include <limits.h> 41*6ba597c5SAnurag S. Maskey #include <libscf.h> 42*6ba597c5SAnurag S. Maskey #include <net/if.h> 43*6ba597c5SAnurag S. Maskey #include <pthread.h> 44*6ba597c5SAnurag S. Maskey #include <pwd.h> 45*6ba597c5SAnurag S. Maskey #include <spawn.h> 46d71dbb73Sjbeck #include <stdarg.h> 47d71dbb73Sjbeck #include <stdio.h> 48d71dbb73Sjbeck #include <stdlib.h> 49d71dbb73Sjbeck #include <string.h> 50*6ba597c5SAnurag S. Maskey #include <strings.h> 51d71dbb73Sjbeck #include <stropts.h> 52d71dbb73Sjbeck #include <sys/socket.h> 53*6ba597c5SAnurag S. Maskey #include <sys/sockio.h> 54*6ba597c5SAnurag S. Maskey #include <sys/types.h> 55*6ba597c5SAnurag S. Maskey #include <unistd.h> 56d71dbb73Sjbeck #include <wait.h> 57d71dbb73Sjbeck #include <zone.h> 58d71dbb73Sjbeck 59*6ba597c5SAnurag S. Maskey #include "util.h" 60*6ba597c5SAnurag S. Maskey #include "llp.h" 61d71dbb73Sjbeck 62d71dbb73Sjbeck extern char **environ; 63*6ba597c5SAnurag S. Maskey extern sigset_t original_sigmask; 64d71dbb73Sjbeck 65*6ba597c5SAnurag S. Maskey /* 66*6ba597c5SAnurag S. Maskey * A holder for all the resources needed to get a property value 67*6ba597c5SAnurag S. Maskey * using libscf. 68*6ba597c5SAnurag S. Maskey */ 69*6ba597c5SAnurag S. Maskey typedef struct scf_resources { 70*6ba597c5SAnurag S. Maskey scf_handle_t *sr_handle; 71*6ba597c5SAnurag S. Maskey scf_instance_t *sr_inst; 72*6ba597c5SAnurag S. Maskey scf_snapshot_t *sr_snap; 73*6ba597c5SAnurag S. Maskey scf_propertygroup_t *sr_pg; 74*6ba597c5SAnurag S. Maskey scf_property_t *sr_prop; 75*6ba597c5SAnurag S. Maskey scf_value_t *sr_val; 76*6ba597c5SAnurag S. Maskey scf_transaction_t *sr_tx; 77*6ba597c5SAnurag S. Maskey scf_transaction_entry_t *sr_ent; 78*6ba597c5SAnurag S. Maskey } scf_resources_t; 79*6ba597c5SAnurag S. Maskey 80*6ba597c5SAnurag S. Maskey static pthread_mutex_t uid_mutex = PTHREAD_MUTEX_INITIALIZER; 81*6ba597c5SAnurag S. Maskey static uid_t uid; 82*6ba597c5SAnurag S. Maskey static int uid_cnt; 83d71dbb73Sjbeck 84*6ba597c5SAnurag S. Maskey void 85*6ba597c5SAnurag S. Maskey nwamd_to_root(void) { 86*6ba597c5SAnurag S. Maskey (void) pthread_mutex_lock(&uid_mutex); 87*6ba597c5SAnurag S. Maskey if (uid == 0) 88*6ba597c5SAnurag S. Maskey uid = getuid(); 89*6ba597c5SAnurag S. Maskey if (uid_cnt++ == 0) { 90*6ba597c5SAnurag S. Maskey nwamd_escalate_privs(); 91*6ba597c5SAnurag S. Maskey if (setuid(0) == -1) 92*6ba597c5SAnurag S. Maskey nlog(LOG_ERR, "setuid(0) failed %s", strerror(errno)); 93d71dbb73Sjbeck } 94*6ba597c5SAnurag S. Maskey (void) pthread_mutex_unlock(&uid_mutex); 95d71dbb73Sjbeck } 96d71dbb73Sjbeck 97b00044a2SJames Carlson void 98*6ba597c5SAnurag S. Maskey nwamd_from_root(void) { 99*6ba597c5SAnurag S. Maskey (void) pthread_mutex_lock(&uid_mutex); 100*6ba597c5SAnurag S. Maskey assert(uid_cnt > 0); 101*6ba597c5SAnurag S. Maskey if (--uid_cnt == 0) { 102*6ba597c5SAnurag S. Maskey if (setuid(uid) == -1) 103*6ba597c5SAnurag S. Maskey nlog(LOG_ERR, "setuid(%d) failed %s", uid, 104*6ba597c5SAnurag S. Maskey strerror(errno)); 105*6ba597c5SAnurag S. Maskey nwamd_drop_unneeded_privs(); 106*6ba597c5SAnurag S. Maskey } 107*6ba597c5SAnurag S. Maskey (void) pthread_mutex_unlock(&uid_mutex); 108b00044a2SJames Carlson } 109b00044a2SJames Carlson 110d71dbb73Sjbeck /* 111d71dbb73Sjbeck * 112d71dbb73Sjbeck * This starts a child process determined by command. If command contains a 113d71dbb73Sjbeck * slash then it is assumed to be a full path; otherwise the path is searched 114d71dbb73Sjbeck * for an executable file with the name command. Command is also used as 115d71dbb73Sjbeck * argv[0] of the new process. The rest of the arguments of the function 116d71dbb73Sjbeck * up to the first NULL make up pointers to arguments of the new process. 117d71dbb73Sjbeck * 118d71dbb73Sjbeck * This function returns child exit status on success and -1 on failure. 119d71dbb73Sjbeck * 120d71dbb73Sjbeck * NOTE: original_sigmask must be set before this function is called. 121d71dbb73Sjbeck */ 122d71dbb73Sjbeck int 123*6ba597c5SAnurag S. Maskey nwamd_start_childv(const char *command, char const * const *argv) 124d71dbb73Sjbeck { 125d71dbb73Sjbeck posix_spawnattr_t attr; 126d71dbb73Sjbeck sigset_t fullset; 127d71dbb73Sjbeck int i, rc, status, n; 128d71dbb73Sjbeck pid_t pid; 129d71dbb73Sjbeck char vbuf[1024]; 130d71dbb73Sjbeck 131d71dbb73Sjbeck vbuf[0] = 0; 132d71dbb73Sjbeck n = sizeof (vbuf); 133d71dbb73Sjbeck for (i = 1; argv[i] != NULL && n > 2; i++) { 134d71dbb73Sjbeck n -= strlcat(vbuf, " ", n); 135d71dbb73Sjbeck n -= strlcat(vbuf, argv[i], n); 136d71dbb73Sjbeck } 137d71dbb73Sjbeck if (argv[i] != NULL || n < 0) 138*6ba597c5SAnurag S. Maskey nlog(LOG_ERR, "nwamd_start_childv can't log full arg vector"); 139d71dbb73Sjbeck 140d71dbb73Sjbeck if ((rc = posix_spawnattr_init(&attr)) != 0) { 141*6ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "posix_spawnattr_init %d %s\n", 142*6ba597c5SAnurag S. Maskey rc, strerror(rc)); 143d71dbb73Sjbeck return (-1); 144d71dbb73Sjbeck } 145d71dbb73Sjbeck (void) sigfillset(&fullset); 146d71dbb73Sjbeck if ((rc = posix_spawnattr_setsigdefault(&attr, &fullset)) != 0) { 147*6ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "setsigdefault %d %s\n", rc, strerror(rc)); 148d71dbb73Sjbeck return (-1); 149d71dbb73Sjbeck } 150d71dbb73Sjbeck if ((rc = posix_spawnattr_setsigmask(&attr, &original_sigmask)) != 0) { 151*6ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "setsigmask %d %s\n", rc, strerror(rc)); 152d71dbb73Sjbeck return (-1); 153d71dbb73Sjbeck } 154d71dbb73Sjbeck if ((rc = posix_spawnattr_setflags(&attr, 155d71dbb73Sjbeck POSIX_SPAWN_SETSIGDEF|POSIX_SPAWN_SETSIGMASK)) != 0) { 156*6ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "setflags %d %s\n", rc, strerror(rc)); 157d71dbb73Sjbeck return (-1); 158d71dbb73Sjbeck } 159d71dbb73Sjbeck 160d71dbb73Sjbeck if ((rc = posix_spawnp(&pid, command, NULL, &attr, (char * const *)argv, 161d71dbb73Sjbeck environ)) > 0) { 162*6ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "posix_spawnp failed errno %d", rc); 163d71dbb73Sjbeck return (-1); 164d71dbb73Sjbeck } 165d71dbb73Sjbeck 166d71dbb73Sjbeck if ((rc = posix_spawnattr_destroy(&attr)) != 0) { 167*6ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "posix_spawn_attr_destroy %d %s\n", 168*6ba597c5SAnurag S. Maskey rc, strerror(rc)); 169d71dbb73Sjbeck return (-1); 170d71dbb73Sjbeck } 171d71dbb73Sjbeck 172d71dbb73Sjbeck (void) waitpid(pid, &status, 0); 173d71dbb73Sjbeck if (WIFSIGNALED(status) || WIFSTOPPED(status)) { 174d71dbb73Sjbeck i = WIFSIGNALED(status) ? WTERMSIG(status) : WSTOPSIG(status); 175*6ba597c5SAnurag S. Maskey nlog(LOG_ERR, "'%s%s' %s with signal %d (%s)", command, vbuf, 176d71dbb73Sjbeck (WIFSIGNALED(status) ? "terminated" : "stopped"), i, 177d71dbb73Sjbeck strsignal(i)); 178d71dbb73Sjbeck return (-2); 179d71dbb73Sjbeck } else { 180*6ba597c5SAnurag S. Maskey nlog(LOG_INFO, "'%s%s' completed normally: %d", command, vbuf, 181d71dbb73Sjbeck WEXITSTATUS(status)); 182d71dbb73Sjbeck return (WEXITSTATUS(status)); 183d71dbb73Sjbeck } 184d71dbb73Sjbeck } 185d71dbb73Sjbeck 186*6ba597c5SAnurag S. Maskey /* 187*6ba597c5SAnurag S. Maskey * For global zone, check if the link is used by a non-global 188*6ba597c5SAnurag S. Maskey * zone, note that the non-global zones doesn't need this check, 189*6ba597c5SAnurag S. Maskey * because zoneadm has taken care of this when the zone boots. 190*6ba597c5SAnurag S. Maskey * In the global zone, we ignore events for local-zone-owned links 191*6ba597c5SAnurag S. Maskey * since these are taken care of by the local zone's network 192*6ba597c5SAnurag S. Maskey * configuration services. 193*6ba597c5SAnurag S. Maskey */ 194*6ba597c5SAnurag S. Maskey boolean_t 195*6ba597c5SAnurag S. Maskey nwamd_link_belongs_to_this_zone(const char *linkname) 196d71dbb73Sjbeck { 197*6ba597c5SAnurag S. Maskey zoneid_t zoneid; 198*6ba597c5SAnurag S. Maskey char zonename[ZONENAME_MAX]; 199*6ba597c5SAnurag S. Maskey int ret; 200*6ba597c5SAnurag S. Maskey 201*6ba597c5SAnurag S. Maskey zoneid = getzoneid(); 202*6ba597c5SAnurag S. Maskey if (zoneid == GLOBAL_ZONEID) { 203*6ba597c5SAnurag S. Maskey datalink_id_t linkid; 204*6ba597c5SAnurag S. Maskey dladm_status_t status; 205*6ba597c5SAnurag S. Maskey char errstr[DLADM_STRSIZE]; 206*6ba597c5SAnurag S. Maskey 207*6ba597c5SAnurag S. Maskey if ((status = dladm_name2info(dld_handle, linkname, &linkid, 208*6ba597c5SAnurag S. Maskey NULL, NULL, NULL)) != DLADM_STATUS_OK) { 209*6ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "nwamd_link_belongs_to_this_zone: " 210*6ba597c5SAnurag S. Maskey "could not get linkid for %s: %s", 211*6ba597c5SAnurag S. Maskey linkname, dladm_status2str(status, errstr)); 212*6ba597c5SAnurag S. Maskey return (B_FALSE); 213*6ba597c5SAnurag S. Maskey } 214*6ba597c5SAnurag S. Maskey zoneid = ALL_ZONES; 215*6ba597c5SAnurag S. Maskey ret = zone_check_datalink(&zoneid, linkid); 216*6ba597c5SAnurag S. Maskey if (ret == 0) { 217*6ba597c5SAnurag S. Maskey (void) getzonenamebyid(zoneid, zonename, ZONENAME_MAX); 218*6ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "nwamd_link_belongs_to_this_zone: " 219*6ba597c5SAnurag S. Maskey "%s is used by non-global zone: %s", 220*6ba597c5SAnurag S. Maskey linkname, zonename); 221*6ba597c5SAnurag S. Maskey return (B_FALSE); 222d71dbb73Sjbeck } 223*6ba597c5SAnurag S. Maskey } 224*6ba597c5SAnurag S. Maskey return (B_TRUE); 225*6ba597c5SAnurag S. Maskey } 226d71dbb73Sjbeck 227*6ba597c5SAnurag S. Maskey void 228*6ba597c5SAnurag S. Maskey nwamd_drop_unneeded_privs(void) 229*6ba597c5SAnurag S. Maskey { 230*6ba597c5SAnurag S. Maskey priv_set_t *priv_set, *allpriv_set; 231*6ba597c5SAnurag S. Maskey 232*6ba597c5SAnurag S. Maskey /* build up our minimal set of privs; start with the basic set */ 233*6ba597c5SAnurag S. Maskey priv_set = priv_str_to_set("basic", ",", NULL); 234*6ba597c5SAnurag S. Maskey allpriv_set = priv_str_to_set("zone", ",", NULL); 235*6ba597c5SAnurag S. Maskey if (priv_set == NULL || allpriv_set == NULL) 236*6ba597c5SAnurag S. Maskey pfail("converting privilege sets: %s", strerror(errno)); 237*6ba597c5SAnurag S. Maskey 238*6ba597c5SAnurag S. Maskey (void) priv_addset(priv_set, PRIV_FILE_CHOWN_SELF); 239*6ba597c5SAnurag S. Maskey (void) priv_addset(priv_set, PRIV_FILE_DAC_READ); 240*6ba597c5SAnurag S. Maskey (void) priv_addset(priv_set, PRIV_FILE_DAC_WRITE); 241*6ba597c5SAnurag S. Maskey (void) priv_addset(priv_set, PRIV_NET_RAWACCESS); 242*6ba597c5SAnurag S. Maskey (void) priv_addset(priv_set, PRIV_NET_PRIVADDR); 243*6ba597c5SAnurag S. Maskey (void) priv_addset(priv_set, PRIV_PROC_AUDIT); 244*6ba597c5SAnurag S. Maskey (void) priv_addset(priv_set, PRIV_PROC_OWNER); 245*6ba597c5SAnurag S. Maskey (void) priv_addset(priv_set, PRIV_PROC_SETID); 246*6ba597c5SAnurag S. Maskey (void) priv_addset(priv_set, PRIV_SYS_CONFIG); 247*6ba597c5SAnurag S. Maskey (void) priv_addset(priv_set, PRIV_SYS_IP_CONFIG); 248*6ba597c5SAnurag S. Maskey (void) priv_addset(priv_set, PRIV_SYS_IPC_CONFIG); 249*6ba597c5SAnurag S. Maskey (void) priv_addset(priv_set, PRIV_SYS_MOUNT); 250*6ba597c5SAnurag S. Maskey (void) priv_addset(priv_set, PRIV_SYS_NET_CONFIG); 251*6ba597c5SAnurag S. Maskey (void) priv_addset(priv_set, PRIV_SYS_RES_CONFIG); 252*6ba597c5SAnurag S. Maskey (void) priv_addset(priv_set, PRIV_SYS_RESOURCE); 253*6ba597c5SAnurag S. Maskey 254*6ba597c5SAnurag S. Maskey /* 255*6ba597c5SAnurag S. Maskey * Since our zone might not have all these privs, 256*6ba597c5SAnurag S. Maskey * just ask for those that are available. 257*6ba597c5SAnurag S. Maskey */ 258*6ba597c5SAnurag S. Maskey priv_intersect(allpriv_set, priv_set); 259*6ba597c5SAnurag S. Maskey 260*6ba597c5SAnurag S. Maskey if (setppriv(PRIV_SET, PRIV_INHERITABLE, priv_set) == -1) { 261*6ba597c5SAnurag S. Maskey priv_freeset(allpriv_set); 262*6ba597c5SAnurag S. Maskey priv_freeset(priv_set); 263*6ba597c5SAnurag S. Maskey pfail("setppriv inheritable: %s", strerror(errno)); 264*6ba597c5SAnurag S. Maskey } 265*6ba597c5SAnurag S. Maskey /* 266*6ba597c5SAnurag S. Maskey * Need to ensure permitted set contains all privs so we can escalate 267*6ba597c5SAnurag S. Maskey * later. 268*6ba597c5SAnurag S. Maskey */ 269*6ba597c5SAnurag S. Maskey if (setppriv(PRIV_SET, PRIV_PERMITTED, allpriv_set) == -1) { 270*6ba597c5SAnurag S. Maskey priv_freeset(allpriv_set); 271*6ba597c5SAnurag S. Maskey priv_freeset(priv_set); 272*6ba597c5SAnurag S. Maskey pfail("setppriv permitted: %s", strerror(errno)); 273*6ba597c5SAnurag S. Maskey } 274*6ba597c5SAnurag S. Maskey /* 275*6ba597c5SAnurag S. Maskey * We need to find a smaller set of privs that are important to us. 276*6ba597c5SAnurag S. Maskey * Otherwise we really are not gaining much by doing this. 277*6ba597c5SAnurag S. Maskey */ 278*6ba597c5SAnurag S. Maskey if (setppriv(PRIV_SET, PRIV_EFFECTIVE, priv_set) == -1) { 279*6ba597c5SAnurag S. Maskey priv_freeset(allpriv_set); 280*6ba597c5SAnurag S. Maskey priv_freeset(priv_set); 281*6ba597c5SAnurag S. Maskey pfail("setppriv effective: %s", strerror(errno)); 282*6ba597c5SAnurag S. Maskey } 283d71dbb73Sjbeck 284*6ba597c5SAnurag S. Maskey priv_freeset(priv_set); 285*6ba597c5SAnurag S. Maskey priv_freeset(allpriv_set); 286*6ba597c5SAnurag S. Maskey } 287d71dbb73Sjbeck 288*6ba597c5SAnurag S. Maskey void 289*6ba597c5SAnurag S. Maskey nwamd_escalate_privs(void) 290*6ba597c5SAnurag S. Maskey { 291*6ba597c5SAnurag S. Maskey priv_set_t *priv_set; 292*6ba597c5SAnurag S. Maskey priv_set = priv_str_to_set("zone", ",", NULL); 293*6ba597c5SAnurag S. Maskey if (priv_set == NULL) 294*6ba597c5SAnurag S. Maskey pfail("creating privilege set: %s", strerror(errno)); 295*6ba597c5SAnurag S. Maskey 296*6ba597c5SAnurag S. Maskey if (setppriv(PRIV_SET, PRIV_EFFECTIVE, priv_set) == -1) { 297*6ba597c5SAnurag S. Maskey priv_freeset(priv_set); 298*6ba597c5SAnurag S. Maskey pfail("setppriv effective: %s", strerror(errno)); 299*6ba597c5SAnurag S. Maskey } 300*6ba597c5SAnurag S. Maskey priv_freeset(priv_set); 301d71dbb73Sjbeck } 302d71dbb73Sjbeck 303*6ba597c5SAnurag S. Maskey /* 304*6ba597c5SAnurag S. Maskey * Inputs: 305*6ba597c5SAnurag S. Maskey * res is a pointer to the scf_resources_t to be released. 306*6ba597c5SAnurag S. Maskey */ 307*6ba597c5SAnurag S. Maskey static void 308*6ba597c5SAnurag S. Maskey release_scf_resources(scf_resources_t *res) 309*6ba597c5SAnurag S. Maskey { 310*6ba597c5SAnurag S. Maskey scf_entry_destroy(res->sr_ent); 311*6ba597c5SAnurag S. Maskey scf_transaction_destroy(res->sr_tx); 312*6ba597c5SAnurag S. Maskey scf_value_destroy(res->sr_val); 313*6ba597c5SAnurag S. Maskey scf_property_destroy(res->sr_prop); 314*6ba597c5SAnurag S. Maskey scf_pg_destroy(res->sr_pg); 315*6ba597c5SAnurag S. Maskey scf_snapshot_destroy(res->sr_snap); 316*6ba597c5SAnurag S. Maskey scf_instance_destroy(res->sr_inst); 317*6ba597c5SAnurag S. Maskey (void) scf_handle_unbind(res->sr_handle); 318*6ba597c5SAnurag S. Maskey scf_handle_destroy(res->sr_handle); 319*6ba597c5SAnurag S. Maskey } 320d71dbb73Sjbeck 321d71dbb73Sjbeck /* 322*6ba597c5SAnurag S. Maskey * Inputs: 323*6ba597c5SAnurag S. Maskey * fmri is the instance to look up 324*6ba597c5SAnurag S. Maskey * Outputs: 325*6ba597c5SAnurag S. Maskey * res is a pointer to an scf_resources_t. This is an internal 326*6ba597c5SAnurag S. Maskey * structure that holds all the handles needed to get a specific 327*6ba597c5SAnurag S. Maskey * property from the running snapshot; on a successful return it 328*6ba597c5SAnurag S. Maskey * contains the scf_value_t that should be passed to the desired 329*6ba597c5SAnurag S. Maskey * scf_value_get_foo() function, and must be freed after use by 330*6ba597c5SAnurag S. Maskey * calling release_scf_resources(). On a failure return, any 331*6ba597c5SAnurag S. Maskey * resources that may have been assigned to res are released, so 332*6ba597c5SAnurag S. Maskey * the caller does not need to do any cleanup in the failure case. 333*6ba597c5SAnurag S. Maskey * Returns: 334*6ba597c5SAnurag S. Maskey * 0 on success 335*6ba597c5SAnurag S. Maskey * -1 on failure 336d71dbb73Sjbeck */ 337*6ba597c5SAnurag S. Maskey 338*6ba597c5SAnurag S. Maskey static int 339*6ba597c5SAnurag S. Maskey create_scf_resources(const char *fmri, scf_resources_t *res) 340*6ba597c5SAnurag S. Maskey { 341*6ba597c5SAnurag S. Maskey res->sr_tx = NULL; 342*6ba597c5SAnurag S. Maskey res->sr_ent = NULL; 343*6ba597c5SAnurag S. Maskey res->sr_inst = NULL; 344*6ba597c5SAnurag S. Maskey res->sr_snap = NULL; 345*6ba597c5SAnurag S. Maskey res->sr_pg = NULL; 346*6ba597c5SAnurag S. Maskey res->sr_prop = NULL; 347*6ba597c5SAnurag S. Maskey res->sr_val = NULL; 348*6ba597c5SAnurag S. Maskey 349*6ba597c5SAnurag S. Maskey if ((res->sr_handle = scf_handle_create(SCF_VERSION)) == NULL) { 350*6ba597c5SAnurag S. Maskey return (-1); 351*6ba597c5SAnurag S. Maskey } 352*6ba597c5SAnurag S. Maskey 353*6ba597c5SAnurag S. Maskey if (scf_handle_bind(res->sr_handle) != 0) { 354*6ba597c5SAnurag S. Maskey scf_handle_destroy(res->sr_handle); 355*6ba597c5SAnurag S. Maskey return (-1); 356*6ba597c5SAnurag S. Maskey } 357*6ba597c5SAnurag S. Maskey if ((res->sr_inst = scf_instance_create(res->sr_handle)) == NULL) { 358*6ba597c5SAnurag S. Maskey goto failure; 359*6ba597c5SAnurag S. Maskey } 360*6ba597c5SAnurag S. Maskey if (scf_handle_decode_fmri(res->sr_handle, fmri, NULL, NULL, 361*6ba597c5SAnurag S. Maskey res->sr_inst, NULL, NULL, SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) { 362*6ba597c5SAnurag S. Maskey goto failure; 363*6ba597c5SAnurag S. Maskey } 364*6ba597c5SAnurag S. Maskey if ((res->sr_snap = scf_snapshot_create(res->sr_handle)) == NULL) { 365*6ba597c5SAnurag S. Maskey goto failure; 366*6ba597c5SAnurag S. Maskey } 367*6ba597c5SAnurag S. Maskey if (scf_instance_get_snapshot(res->sr_inst, "running", 368*6ba597c5SAnurag S. Maskey res->sr_snap) != 0) { 369*6ba597c5SAnurag S. Maskey goto failure; 370*6ba597c5SAnurag S. Maskey } 371*6ba597c5SAnurag S. Maskey if ((res->sr_pg = scf_pg_create(res->sr_handle)) == NULL) { 372*6ba597c5SAnurag S. Maskey goto failure; 373*6ba597c5SAnurag S. Maskey } 374*6ba597c5SAnurag S. Maskey if ((res->sr_prop = scf_property_create(res->sr_handle)) == NULL) { 375*6ba597c5SAnurag S. Maskey goto failure; 376*6ba597c5SAnurag S. Maskey } 377*6ba597c5SAnurag S. Maskey if ((res->sr_val = scf_value_create(res->sr_handle)) == NULL) { 378*6ba597c5SAnurag S. Maskey goto failure; 379*6ba597c5SAnurag S. Maskey } 380*6ba597c5SAnurag S. Maskey if ((res->sr_tx = scf_transaction_create(res->sr_handle)) == NULL) { 381*6ba597c5SAnurag S. Maskey goto failure; 382*6ba597c5SAnurag S. Maskey } 383*6ba597c5SAnurag S. Maskey if ((res->sr_ent = scf_entry_create(res->sr_handle)) == NULL) { 384*6ba597c5SAnurag S. Maskey goto failure; 385*6ba597c5SAnurag S. Maskey } 386*6ba597c5SAnurag S. Maskey return (0); 387*6ba597c5SAnurag S. Maskey 388*6ba597c5SAnurag S. Maskey failure: 389*6ba597c5SAnurag S. Maskey nlog(LOG_ERR, "create_scf_resources failed: %s", 390*6ba597c5SAnurag S. Maskey scf_strerror(scf_error())); 391*6ba597c5SAnurag S. Maskey release_scf_resources(res); 392*6ba597c5SAnurag S. Maskey return (-1); 393*6ba597c5SAnurag S. Maskey } 394*6ba597c5SAnurag S. Maskey 395*6ba597c5SAnurag S. Maskey /* 396*6ba597c5SAnurag S. Maskey * Inputs: 397*6ba597c5SAnurag S. Maskey * fmri is the instance to look up 398*6ba597c5SAnurag S. Maskey * pg is the property group to look up 399*6ba597c5SAnurag S. Maskey * prop is the property within that group to look up 400*6ba597c5SAnurag S. Maskey * running specifies if running snapshot is to be used 401*6ba597c5SAnurag S. Maskey * Outputs: 402*6ba597c5SAnurag S. Maskey * res is a pointer to an scf_resources_t. This is an internal 403*6ba597c5SAnurag S. Maskey * structure that holds all the handles needed to get a specific 404*6ba597c5SAnurag S. Maskey * property from the running snapshot; on a successful return it 405*6ba597c5SAnurag S. Maskey * contains the scf_value_t that should be passed to the desired 406*6ba597c5SAnurag S. Maskey * scf_value_get_foo() function, and must be freed after use by 407*6ba597c5SAnurag S. Maskey * calling release_scf_resources(). On a failure return, any 408*6ba597c5SAnurag S. Maskey * resources that may have been assigned to res are released, so 409*6ba597c5SAnurag S. Maskey * the caller does not need to do any cleanup in the failure case. 410*6ba597c5SAnurag S. Maskey * Returns: 411*6ba597c5SAnurag S. Maskey * 0 on success 412*6ba597c5SAnurag S. Maskey * -1 on failure 413*6ba597c5SAnurag S. Maskey */ 414*6ba597c5SAnurag S. Maskey static int 415*6ba597c5SAnurag S. Maskey get_property_value(const char *fmri, const char *pg, const char *prop, 416*6ba597c5SAnurag S. Maskey boolean_t running, scf_resources_t *res) 417d71dbb73Sjbeck { 418*6ba597c5SAnurag S. Maskey if (create_scf_resources(fmri, res) != 0) 419*6ba597c5SAnurag S. Maskey return (-1); 420*6ba597c5SAnurag S. Maskey 421*6ba597c5SAnurag S. Maskey if (scf_instance_get_pg_composed(res->sr_inst, 422*6ba597c5SAnurag S. Maskey running ? res->sr_snap : NULL, pg, res->sr_pg) != 0) { 423*6ba597c5SAnurag S. Maskey goto failure; 424*6ba597c5SAnurag S. Maskey } 425*6ba597c5SAnurag S. Maskey if (scf_pg_get_property(res->sr_pg, prop, res->sr_prop) != 0) { 426*6ba597c5SAnurag S. Maskey goto failure; 427*6ba597c5SAnurag S. Maskey } 428*6ba597c5SAnurag S. Maskey if (scf_property_get_value(res->sr_prop, res->sr_val) != 0) { 429*6ba597c5SAnurag S. Maskey goto failure; 430*6ba597c5SAnurag S. Maskey } 431*6ba597c5SAnurag S. Maskey return (0); 432d71dbb73Sjbeck 433*6ba597c5SAnurag S. Maskey failure: 434*6ba597c5SAnurag S. Maskey release_scf_resources(res); 435*6ba597c5SAnurag S. Maskey return (-1); 436d71dbb73Sjbeck } 437d71dbb73Sjbeck 438*6ba597c5SAnurag S. Maskey /* 439*6ba597c5SAnurag S. Maskey * Inputs: 440*6ba597c5SAnurag S. Maskey * lfmri is the instance fmri to look up 441*6ba597c5SAnurag S. Maskey * lpg is the property group to look up 442*6ba597c5SAnurag S. Maskey * lprop is the property within that group to look up 443*6ba597c5SAnurag S. Maskey * Outputs: 444*6ba597c5SAnurag S. Maskey * answer is a pointer to the property value 445*6ba597c5SAnurag S. Maskey * Returns: 446*6ba597c5SAnurag S. Maskey * 0 on success 447*6ba597c5SAnurag S. Maskey * -1 on failure 448*6ba597c5SAnurag S. Maskey * If successful, the property value is retured in *answer. 449*6ba597c5SAnurag S. Maskey * Otherwise, *answer is undefined, and it is up to the caller to decide 450*6ba597c5SAnurag S. Maskey * how to handle that case. 451*6ba597c5SAnurag S. Maskey */ 452*6ba597c5SAnurag S. Maskey int 453*6ba597c5SAnurag S. Maskey nwamd_lookup_boolean_property(const char *lfmri, const char *lpg, 454*6ba597c5SAnurag S. Maskey const char *lprop, boolean_t *answer) 455*6ba597c5SAnurag S. Maskey { 456*6ba597c5SAnurag S. Maskey int result = -1; 457*6ba597c5SAnurag S. Maskey scf_resources_t res; 458*6ba597c5SAnurag S. Maskey uint8_t prop_val; 459*6ba597c5SAnurag S. Maskey 460*6ba597c5SAnurag S. Maskey if (get_property_value(lfmri, lpg, lprop, B_TRUE, &res) != 0) { 461*6ba597c5SAnurag S. Maskey 462*6ba597c5SAnurag S. Maskey /* 463*6ba597c5SAnurag S. Maskey * an error was already logged by get_property_value, 464*6ba597c5SAnurag S. Maskey * and it released any resources assigned to res before 465*6ba597c5SAnurag S. Maskey * returning. 466*6ba597c5SAnurag S. Maskey */ 467*6ba597c5SAnurag S. Maskey return (result); 468*6ba597c5SAnurag S. Maskey } 469*6ba597c5SAnurag S. Maskey if (scf_value_get_boolean(res.sr_val, &prop_val) != 0) { 470*6ba597c5SAnurag S. Maskey goto cleanup; 471*6ba597c5SAnurag S. Maskey } 472*6ba597c5SAnurag S. Maskey *answer = (boolean_t)prop_val; 473*6ba597c5SAnurag S. Maskey result = 0; 474*6ba597c5SAnurag S. Maskey cleanup: 475*6ba597c5SAnurag S. Maskey release_scf_resources(&res); 476*6ba597c5SAnurag S. Maskey return (result); 477*6ba597c5SAnurag S. Maskey } 478*6ba597c5SAnurag S. Maskey 479*6ba597c5SAnurag S. Maskey /* 480*6ba597c5SAnurag S. Maskey * Inputs: 481*6ba597c5SAnurag S. Maskey * lfmri is the instance fmri to look up 482*6ba597c5SAnurag S. Maskey * lpg is the property group to look up 483*6ba597c5SAnurag S. Maskey * lprop is the property within that group to look up 484*6ba597c5SAnurag S. Maskey * buf is the place to put the answer 485*6ba597c5SAnurag S. Maskey * bufsz is the size of buf 486*6ba597c5SAnurag S. Maskey * Outputs: 487*6ba597c5SAnurag S. Maskey * 488*6ba597c5SAnurag S. Maskey * Returns: 489*6ba597c5SAnurag S. Maskey * 0 on success 490*6ba597c5SAnurag S. Maskey * -1 on failure 491*6ba597c5SAnurag S. Maskey * If successful, the property value is retured in buf. 492*6ba597c5SAnurag S. Maskey * Otherwise, buf is undefined, and it is up to the caller to decide 493*6ba597c5SAnurag S. Maskey * how to handle that case. 494*6ba597c5SAnurag S. Maskey */ 495*6ba597c5SAnurag S. Maskey int 496*6ba597c5SAnurag S. Maskey nwamd_lookup_string_property(const char *lfmri, const char *lpg, 497*6ba597c5SAnurag S. Maskey const char *lprop, char *buf, size_t bufsz) 498d71dbb73Sjbeck { 499*6ba597c5SAnurag S. Maskey int result = -1; 500*6ba597c5SAnurag S. Maskey scf_resources_t res; 501*6ba597c5SAnurag S. Maskey 502*6ba597c5SAnurag S. Maskey if (get_property_value(lfmri, lpg, lprop, B_TRUE, &res) != 0) { 503*6ba597c5SAnurag S. Maskey /* 504*6ba597c5SAnurag S. Maskey * The above function fails when trying to get a 505*6ba597c5SAnurag S. Maskey * non-persistent property group from the running snapshot. 506*6ba597c5SAnurag S. Maskey * Try going for the non-running snapshot. 507*6ba597c5SAnurag S. Maskey */ 508*6ba597c5SAnurag S. Maskey if (get_property_value(lfmri, lpg, lprop, B_FALSE, &res) != 0) { 509*6ba597c5SAnurag S. Maskey /* 510*6ba597c5SAnurag S. Maskey * an error was already logged by get_property_value, 511*6ba597c5SAnurag S. Maskey * and it released any resources assigned to res before 512*6ba597c5SAnurag S. Maskey * returning. 513*6ba597c5SAnurag S. Maskey */ 514*6ba597c5SAnurag S. Maskey return (result); 515*6ba597c5SAnurag S. Maskey } 516*6ba597c5SAnurag S. Maskey } 517*6ba597c5SAnurag S. Maskey if (scf_value_get_astring(res.sr_val, buf, bufsz) == 0) 518*6ba597c5SAnurag S. Maskey goto cleanup; 519*6ba597c5SAnurag S. Maskey 520*6ba597c5SAnurag S. Maskey result = 0; 521*6ba597c5SAnurag S. Maskey cleanup: 522*6ba597c5SAnurag S. Maskey release_scf_resources(&res); 523*6ba597c5SAnurag S. Maskey return (result); 524*6ba597c5SAnurag S. Maskey } 525d71dbb73Sjbeck 526*6ba597c5SAnurag S. Maskey /* 527*6ba597c5SAnurag S. Maskey * Inputs: 528*6ba597c5SAnurag S. Maskey * lfmri is the instance fmri to look up 529*6ba597c5SAnurag S. Maskey * lpg is the property group to look up 530*6ba597c5SAnurag S. Maskey * lprop is the property within that group to look up 531*6ba597c5SAnurag S. Maskey * Outputs: 532*6ba597c5SAnurag S. Maskey * answer is a pointer to the property value 533*6ba597c5SAnurag S. Maskey * Returns: 534*6ba597c5SAnurag S. Maskey * 0 on success 535*6ba597c5SAnurag S. Maskey * -1 on failure 536*6ba597c5SAnurag S. Maskey * If successful, the property value is retured in *answer. 537*6ba597c5SAnurag S. Maskey * Otherwise, *answer is undefined, and it is up to the caller to decide 538*6ba597c5SAnurag S. Maskey * how to handle that case. 539*6ba597c5SAnurag S. Maskey */ 540*6ba597c5SAnurag S. Maskey int 541*6ba597c5SAnurag S. Maskey nwamd_lookup_count_property(const char *lfmri, const char *lpg, 542*6ba597c5SAnurag S. Maskey const char *lprop, uint64_t *answer) 543*6ba597c5SAnurag S. Maskey { 544*6ba597c5SAnurag S. Maskey int result = -1; 545*6ba597c5SAnurag S. Maskey scf_resources_t res; 546*6ba597c5SAnurag S. Maskey 547*6ba597c5SAnurag S. Maskey if (get_property_value(lfmri, lpg, lprop, B_TRUE, &res) != 0) { 548*6ba597c5SAnurag S. Maskey 549*6ba597c5SAnurag S. Maskey /* 550*6ba597c5SAnurag S. Maskey * an error was already logged by get_property_value, 551*6ba597c5SAnurag S. Maskey * and it released any resources assigned to res before 552*6ba597c5SAnurag S. Maskey * returning. 553*6ba597c5SAnurag S. Maskey */ 554*6ba597c5SAnurag S. Maskey return (result); 555*6ba597c5SAnurag S. Maskey } 556*6ba597c5SAnurag S. Maskey if (scf_value_get_count(res.sr_val, answer) != 0) { 557*6ba597c5SAnurag S. Maskey goto cleanup; 558*6ba597c5SAnurag S. Maskey } 559*6ba597c5SAnurag S. Maskey result = 0; 560*6ba597c5SAnurag S. Maskey cleanup: 561*6ba597c5SAnurag S. Maskey release_scf_resources(&res); 562*6ba597c5SAnurag S. Maskey return (result); 563*6ba597c5SAnurag S. Maskey } 564*6ba597c5SAnurag S. Maskey 565*6ba597c5SAnurag S. Maskey static int 566*6ba597c5SAnurag S. Maskey set_property_value(scf_resources_t *res, const char *propname, 567*6ba597c5SAnurag S. Maskey scf_type_t proptype) 568*6ba597c5SAnurag S. Maskey { 569*6ba597c5SAnurag S. Maskey int result = -1; 570*6ba597c5SAnurag S. Maskey boolean_t new; 571*6ba597c5SAnurag S. Maskey 572*6ba597c5SAnurag S. Maskey retry: 573*6ba597c5SAnurag S. Maskey new = (scf_pg_get_property(res->sr_pg, propname, res->sr_prop) != 0); 574*6ba597c5SAnurag S. Maskey 575*6ba597c5SAnurag S. Maskey if (scf_transaction_start(res->sr_tx, res->sr_pg) == -1) { 576*6ba597c5SAnurag S. Maskey goto failure; 577*6ba597c5SAnurag S. Maskey } 578*6ba597c5SAnurag S. Maskey if (new) { 579*6ba597c5SAnurag S. Maskey if (scf_transaction_property_new(res->sr_tx, res->sr_ent, 580*6ba597c5SAnurag S. Maskey propname, proptype) == -1) { 581*6ba597c5SAnurag S. Maskey goto failure; 582*6ba597c5SAnurag S. Maskey } 583*6ba597c5SAnurag S. Maskey } else { 584*6ba597c5SAnurag S. Maskey if (scf_transaction_property_change(res->sr_tx, res->sr_ent, 585*6ba597c5SAnurag S. Maskey propname, proptype) == -1) { 586*6ba597c5SAnurag S. Maskey goto failure; 587*6ba597c5SAnurag S. Maskey } 588*6ba597c5SAnurag S. Maskey } 589*6ba597c5SAnurag S. Maskey 590*6ba597c5SAnurag S. Maskey if (scf_entry_add_value(res->sr_ent, res->sr_val) != 0) { 591*6ba597c5SAnurag S. Maskey goto failure; 592*6ba597c5SAnurag S. Maskey } 593*6ba597c5SAnurag S. Maskey 594*6ba597c5SAnurag S. Maskey result = scf_transaction_commit(res->sr_tx); 595*6ba597c5SAnurag S. Maskey if (result == 0) { 596*6ba597c5SAnurag S. Maskey scf_transaction_reset(res->sr_tx); 597*6ba597c5SAnurag S. Maskey if (scf_pg_update(res->sr_pg) == -1) { 598*6ba597c5SAnurag S. Maskey goto failure; 599*6ba597c5SAnurag S. Maskey } 600*6ba597c5SAnurag S. Maskey nlog(LOG_INFO, "set_property_value: transaction commit failed " 601*6ba597c5SAnurag S. Maskey "for %s; retrying", propname); 602*6ba597c5SAnurag S. Maskey goto retry; 603*6ba597c5SAnurag S. Maskey } 604*6ba597c5SAnurag S. Maskey if (result == -1) 605*6ba597c5SAnurag S. Maskey goto failure; 606*6ba597c5SAnurag S. Maskey return (0); 607*6ba597c5SAnurag S. Maskey 608*6ba597c5SAnurag S. Maskey failure: 609*6ba597c5SAnurag S. Maskey return (-1); 610*6ba597c5SAnurag S. Maskey } 611*6ba597c5SAnurag S. Maskey 612*6ba597c5SAnurag S. Maskey int 613*6ba597c5SAnurag S. Maskey nwamd_set_count_property(const char *fmri, const char *pg, const char *prop, 614*6ba597c5SAnurag S. Maskey uint64_t count) 615*6ba597c5SAnurag S. Maskey { 616*6ba597c5SAnurag S. Maskey scf_resources_t res; 617*6ba597c5SAnurag S. Maskey 618*6ba597c5SAnurag S. Maskey if (create_scf_resources(fmri, &res) != 0) 619*6ba597c5SAnurag S. Maskey return (-1); 620*6ba597c5SAnurag S. Maskey 621*6ba597c5SAnurag S. Maskey if (scf_instance_add_pg(res.sr_inst, pg, SCF_GROUP_APPLICATION, 622*6ba597c5SAnurag S. Maskey SCF_PG_FLAG_NONPERSISTENT, res.sr_pg) != 0) { 623*6ba597c5SAnurag S. Maskey if (scf_error() != SCF_ERROR_EXISTS) 624*6ba597c5SAnurag S. Maskey goto failure; 625*6ba597c5SAnurag S. Maskey if (scf_instance_get_pg_composed(res.sr_inst, NULL, pg, 626*6ba597c5SAnurag S. Maskey res.sr_pg) != 0) 627*6ba597c5SAnurag S. Maskey goto failure; 628*6ba597c5SAnurag S. Maskey } 629*6ba597c5SAnurag S. Maskey 630*6ba597c5SAnurag S. Maskey scf_value_set_count(res.sr_val, (uint64_t)count); 631*6ba597c5SAnurag S. Maskey 632*6ba597c5SAnurag S. Maskey if (set_property_value(&res, prop, SCF_TYPE_COUNT) != 0) 633*6ba597c5SAnurag S. Maskey goto failure; 634*6ba597c5SAnurag S. Maskey 635*6ba597c5SAnurag S. Maskey release_scf_resources(&res); 636*6ba597c5SAnurag S. Maskey return (0); 637*6ba597c5SAnurag S. Maskey 638*6ba597c5SAnurag S. Maskey failure: 639*6ba597c5SAnurag S. Maskey nlog(LOG_INFO, "nwamd_set_count_property: scf failure %s while " 640*6ba597c5SAnurag S. Maskey "setting %s", scf_strerror(scf_error()), prop); 641*6ba597c5SAnurag S. Maskey release_scf_resources(&res); 642*6ba597c5SAnurag S. Maskey return (-1); 643*6ba597c5SAnurag S. Maskey } 644*6ba597c5SAnurag S. Maskey 645*6ba597c5SAnurag S. Maskey int 646*6ba597c5SAnurag S. Maskey nwamd_set_string_property(const char *fmri, const char *pg, const char *prop, 647*6ba597c5SAnurag S. Maskey const char *str) 648*6ba597c5SAnurag S. Maskey { 649*6ba597c5SAnurag S. Maskey scf_resources_t res; 650*6ba597c5SAnurag S. Maskey 651*6ba597c5SAnurag S. Maskey if (create_scf_resources(fmri, &res) != 0) 652*6ba597c5SAnurag S. Maskey return (-1); 653*6ba597c5SAnurag S. Maskey 654*6ba597c5SAnurag S. Maskey if (scf_instance_add_pg(res.sr_inst, pg, SCF_GROUP_APPLICATION, 655*6ba597c5SAnurag S. Maskey SCF_PG_FLAG_NONPERSISTENT, res.sr_pg) != 0) { 656*6ba597c5SAnurag S. Maskey if (scf_error() != SCF_ERROR_EXISTS) 657*6ba597c5SAnurag S. Maskey goto failure; 658*6ba597c5SAnurag S. Maskey if (scf_instance_get_pg_composed(res.sr_inst, NULL, pg, 659*6ba597c5SAnurag S. Maskey res.sr_pg) != 0) 660*6ba597c5SAnurag S. Maskey goto failure; 661*6ba597c5SAnurag S. Maskey } 662*6ba597c5SAnurag S. Maskey 663*6ba597c5SAnurag S. Maskey if (scf_value_set_astring(res.sr_val, str) != 0) 664*6ba597c5SAnurag S. Maskey goto failure; 665*6ba597c5SAnurag S. Maskey 666*6ba597c5SAnurag S. Maskey if (set_property_value(&res, prop, SCF_TYPE_ASTRING) != 0) 667*6ba597c5SAnurag S. Maskey goto failure; 668*6ba597c5SAnurag S. Maskey 669*6ba597c5SAnurag S. Maskey release_scf_resources(&res); 670*6ba597c5SAnurag S. Maskey return (0); 671*6ba597c5SAnurag S. Maskey 672*6ba597c5SAnurag S. Maskey failure: 673*6ba597c5SAnurag S. Maskey nlog(LOG_INFO, "nwamd_set_string_property: scf failure %s while " 674*6ba597c5SAnurag S. Maskey "setting %s", scf_strerror(scf_error()), prop); 675*6ba597c5SAnurag S. Maskey release_scf_resources(&res); 676*6ba597c5SAnurag S. Maskey return (-1); 677*6ba597c5SAnurag S. Maskey } 678*6ba597c5SAnurag S. Maskey 679*6ba597c5SAnurag S. Maskey /* 680*6ba597c5SAnurag S. Maskey * Deletes property prop from property group pg in SMF instance fmri. 681*6ba597c5SAnurag S. Maskey * Returns 0 on success, -1 on failure. 682*6ba597c5SAnurag S. Maskey */ 683*6ba597c5SAnurag S. Maskey int 684*6ba597c5SAnurag S. Maskey nwamd_delete_scf_property(const char *fmri, const char *pg, const char *prop) 685*6ba597c5SAnurag S. Maskey { 686*6ba597c5SAnurag S. Maskey scf_resources_t res; 687*6ba597c5SAnurag S. Maskey int result = -1; 688*6ba597c5SAnurag S. Maskey 689*6ba597c5SAnurag S. Maskey if (create_scf_resources(fmri, &res) != 0) 690*6ba597c5SAnurag S. Maskey return (-1); 691*6ba597c5SAnurag S. Maskey 692*6ba597c5SAnurag S. Maskey if (scf_instance_add_pg(res.sr_inst, pg, SCF_GROUP_APPLICATION, 693*6ba597c5SAnurag S. Maskey SCF_PG_FLAG_NONPERSISTENT, res.sr_pg) != 0) { 694*6ba597c5SAnurag S. Maskey if (scf_error() != SCF_ERROR_EXISTS) 695*6ba597c5SAnurag S. Maskey goto failure; 696*6ba597c5SAnurag S. Maskey if (scf_instance_get_pg_composed(res.sr_inst, NULL, pg, 697*6ba597c5SAnurag S. Maskey res.sr_pg) != 0) 698*6ba597c5SAnurag S. Maskey goto failure; 699*6ba597c5SAnurag S. Maskey } 700*6ba597c5SAnurag S. Maskey 701*6ba597c5SAnurag S. Maskey if (scf_pg_get_property(res.sr_pg, prop, res.sr_prop) != 0) 702*6ba597c5SAnurag S. Maskey goto failure; 703*6ba597c5SAnurag S. Maskey retry: 704*6ba597c5SAnurag S. Maskey if (scf_transaction_start(res.sr_tx, res.sr_pg) == -1) 705*6ba597c5SAnurag S. Maskey goto failure; 706*6ba597c5SAnurag S. Maskey 707*6ba597c5SAnurag S. Maskey if (scf_transaction_property_delete(res.sr_tx, res.sr_ent, prop) == -1) 708*6ba597c5SAnurag S. Maskey goto failure; 709*6ba597c5SAnurag S. Maskey 710*6ba597c5SAnurag S. Maskey result = scf_transaction_commit(res.sr_tx); 711*6ba597c5SAnurag S. Maskey if (result == 0) { 712*6ba597c5SAnurag S. Maskey scf_transaction_reset(res.sr_tx); 713*6ba597c5SAnurag S. Maskey if (scf_pg_update(res.sr_pg) == -1) 714*6ba597c5SAnurag S. Maskey goto failure; 715*6ba597c5SAnurag S. Maskey goto retry; 716*6ba597c5SAnurag S. Maskey } 717*6ba597c5SAnurag S. Maskey if (result == -1) 718*6ba597c5SAnurag S. Maskey goto failure; 719*6ba597c5SAnurag S. Maskey 720*6ba597c5SAnurag S. Maskey release_scf_resources(&res); 721*6ba597c5SAnurag S. Maskey return (0); 722*6ba597c5SAnurag S. Maskey failure: 723*6ba597c5SAnurag S. Maskey release_scf_resources(&res); 724*6ba597c5SAnurag S. Maskey return (-1); 725d71dbb73Sjbeck } 726